我好想逃却逃不掉
总的来说就是搜索,深度优先搜索或广度优先搜索均可,这里采用广度优先搜索
题目:
在一个 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;
}