豆包MarsCode AI 刷题

136 阅读3分钟

我好想逃却逃不掉

总的来说就是搜索,深度优先搜索或广度优先搜索均可,这里采用广度优先搜索

题目:

在一个 N × M 的竞技场迷宫中,你的任务是找出在迷宫中,所有"危险位置"的数量。
"危险位置"定义为:如果站在该位置上,无论采取什么移动策略,都无法到达出口

竞技场中包含以下几种元素:

  • .:表示普通地板,可以自由移动到上下左右相邻的格子(不可以走斜线)
  • O:表示出口
  • U:表示向上的传送器,踩上去会被强制传送到上方的格子
  • D:表示向下的传送器,踩上去会被强制传送到下方的格子
  • L:表示向左的传送器,踩上去会被强制传送到左方的格子
  • R:表示向右的传送器,踩上去会被强制传送到右方的格子

注意,如果被传送出了竞技场之外,则算作死亡。
样例1:

输入:N = 5, M = 5, data = [ [".", ".", ".", ".", "."], [".", "R", "R", "D", "."], [".", "U", ".", "D", "R"], [".", "U", "L", "L", "."], [".", ".", ".", ".", "O"] ]
输出:10
解释:存在 10 个位置,如果站在这些位置上,将永远无法到达右下角的出口(用 X 标记):
['.', '.', '.', '.', '.']
['.', 'X', 'X', 'X', '.']
['.', 'X', 'X', 'X', 'X']
['.', 'X', 'X', 'X', '.']
['.', '.', '.', '.', 'O']

思路

这道题正着找不好找,因为有一些环路,一个个点去试的话开销太大,而且没有办法利用求解其他点时得到的信息。所以我们反着找:从出口开始广度优先搜索,能搜索到的格子就是安全的格子,剩下的就是危险的

按如下规则将给定的二维数组转化为有向图:
数组中的每个元素(即“格子”)对应图中的一个节点
对每个节点,如果在二维数组中,其上方的元素为.D,则有一条指向其上方元素对应的节点的边
其余方向同理

具体地说,就是首先找到O所在的位置,将该节点入队,然后每次考察队首的节点,按照上述规则将其邻接到的且未访问过的节点入队,并令队首元素出队。重复以上过程直至队列为空为止。在搜索的同时统计安全点的数量safeNum,最终返回N * M - safeNum即可。

总结

考察了些许图论的基础知识,是一道基础题。
顺便一提,这道题让我想起了大一时C语言的大作业,我当时做的迷宫自动寻路,也是这种每次移动到上下左右的格子。当时还觉得好高级。

代码

最后附上代码

public static int solution(int N, int M, char[][] data) {
    boolean[][] visited = new boolean[N][];
    int safeNum = 0;
    for (int i = 0; i < visited.length; i++) {
        visited[i] = new boolean[M];
    }
    Queue<Point> queue = new ConcurrentLinkedQueue<>();
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (data[i][j] == 'O') {
                queue.add(new Point(i, j));
                visited[i][j] = true;
                safeNum++;
            }
        }
    }
    while (!queue.isEmpty()) {
        Point peak = queue.poll();
        char nextPoint;
        if (peak.x < N - 1 && !visited[peak.x + 1][peak.y]) {
            nextPoint = data[peak.x + 1][peak.y];
            if (nextPoint == '.' || nextPoint == 'U') {
                queue.add(new Point(peak.x + 1, peak.y));
                visited[peak.x + 1][peak.y] = true;
                safeNum++;
            }
        }
        if (peak.x > 0 && !visited[peak.x - 1][peak.y]) {
            nextPoint = data[peak.x - 1][peak.y];
            if (nextPoint == '.' || nextPoint == 'D') {
                queue.add(new Point(peak.x - 1, peak.y));
                visited[peak.x - 1][peak.y] = true;
                safeNum++;
            }
        }
        if (peak.y < M - 1 && !visited[peak.x][peak.y + 1]) {
            nextPoint = data[peak.x][peak.y + 1];
            if (nextPoint == '.' || nextPoint == 'L') {
                queue.add(new Point(peak.x, peak.y + 1));
                visited[peak.x][peak.y + 1] = true;
                safeNum++;
            }
        }
        if (peak.y > 0 && !visited[peak.x][peak.y - 1]) {
            nextPoint = data[peak.x][peak.y - 1];
            if (nextPoint == '.' || nextPoint == 'R') {
                queue.add(new Point(peak.x, peak.y - 1));
                visited[peak.x][peak.y - 1] = true;
                safeNum++;
            }
        }
    }
    return N * M - safeNum;
}