我好想逃却逃不掉 | 豆包MarsCode AI 刷题

159 阅读4分钟

问题描述

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

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

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

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


输入参数

  • N: 一个整数,表示竞技场地图的行数
  • M: 一个整数,表示竞技场地图的列数
  • data: 一个字符二维数组,表示竞技场地板地图。数组大小为 N × M,其中 1 ≤ N, M ≤ 100

测试样例

样例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']

样例2:

输入:N = 4, M = 4, data = [[".", "R", ".", "O"], ["U", ".", "L", "."], [".", "D", ".", "."], [".", ".", "R", "D"]]
输出:2

样例3:

输入:N = 3, M = 3, data = [[".", "U", "O"], ["L", ".", "R"], ["D", ".", "."]]
输出:8

题解分析

这道题的分类是一道简单题目,但是其涉及到的思想还是很有分析讨论价值的,可以归类为很经典的图的深度/广度优先搜索问题,但是在这之前,我们需要深刻理解题目含义,以及题目约束条件所带来的影响。

如果询问AI的话,他会告诉我们这个问题可以分成三个步骤进行,首先找到迷宫中代表出口的点所在的坐标,然后从出口开始进行深度优先搜索或者广度优先搜索,最后对于无法访问到的点进行统计。

简单看这似乎没有任何问题,这道题目就应该这样去做。但是仔细分析,这个思路存在很多潜在问题,比如出口可以到达的节点并不意味着该节点可以走向出口,有可能他们之间的路径是单方向的。同时出口到达不了的点也并不意味着该节点并不能够到达终点。

所以首先我们需要对这道题的题目条件进行分析,分析出我们可以用一个有向图对迷宫信息进行存储。 即:

  • "."表示该节点到其他各个方向都有有向边
  • "U"DL,R则表示它们只对上/下左/右有出边

根据以上信息我们就可以构建一个存储迷宫信息的有向图了,graph存储邻接表

for i in range(N):
        for j in range(M):
                graph[(i, j)] = []
                # 普通地板和传送器的连接
                if maze[i][j] == '.':
                    if i > 0:  # 上
                        graph[(i, j)].append((i - 1, j))
                    if i < N - 1:  # 下
                        graph[(i, j)].append((i + 1, j))
                    if j > 0:  # 左
                        graph[(i, j)].append((i, j - 1))
                    if j < M - 1:  # 右
                        graph[(i, j)].append((i, j + 1))
                elif maze[i][j] == 'U' and i > 0:  # 向上传送
                    graph[(i, j)].append((i - 1, j))
                elif maze[i][j] == 'D' and i < N - 1:  # 向下传送
                    graph[(i, j)].append((i + 1, j))
                elif maze[i][j] == 'L' and j > 0:  # 向左传送
                    graph[(i, j)].append((i, j - 1))
                elif maze[i][j] == 'R' and j < M - 1:  # 向右传送
                    graph[(i, j)].append((i, j + 1))

从出口进行搜索,需要将有向图转换成反向的,即如果A能够到达B,则应从B进行搜索能够搜到A


def convert_to_reverse_graph(graph):
    reverse_graph = {}
    for node, neighbors in graph.items():
        if node not in reverse_graph:
            reverse_graph[node] = []
        for neighbor in neighbors:
            if neighbor not in reverse_graph:
                reverse_graph[neighbor] = []
            reverse_graph[neighbor].append(node)  # 反向边

    return reverse_graph

最后从出口进行深度/广度优先搜索,利用visited存储访问过的节点即可。

def dfs(reverse_graph, start, visited):
    stack = [start]
    while stack:
        current = stack.pop()
        for neighbor in reverse_graph.get(current, []):
            if neighbor not in visited:
                visited.add(neighbor)
                stack.append(neighbor)

没有出现在visited中的节点即无法到达出口的节点。

===

小白作者欢迎指教。