问题描述
曾经的我不过是一介草民,混迹市井,默默无名。直到我被罗马的士兵从家乡捉走丢进竞技场……
对手出现了,我架紧盾牌想要防御,只觉得巨大的冲击力有如一面城墙冲涌而来,击碎了我的盾牌,我两眼发昏,沉重的身躯轰然倒地。
——我好想逃。
但罗马最大的竞技场,哪有这么容易逃得掉。工程师们早就在地上装了传送机关,虽不会伤人,却会将站在上面的人传到它指向的位置。若是几个传送机关围成一个环,不小心踩在上面的人就会被一圈圈地反复传送……想到这里,我不由得打了个寒颤。必须避开这些危险的地方!
在一个 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
题目描述了一个竞技场迷宫的场景,目标是找出所有“危险位置”的数量。所谓“危险位置”是指站在该位置上无论如何移动都无法到达出口。我们需要考虑竞技场中的普通地板以及传送器,它们可能改变玩家的位置。要解决这个问题,我们可以采用图的遍历算法,具体来说,是用反向的广度优先搜索(BFS)或者深度优先搜索(DFS)来从出口位置反向查找哪些格子是无法到达的。
思路:
-
反向搜索:
- 从出口位置
O开始进行广度优先搜索(BFS)或者深度优先搜索(DFS),标记所有能够到达出口的位置。 - 然后遍历整个竞技场,将不能到达出口的格子视为“危险位置”。
- 从出口位置
-
传送器的处理:
- 传送器(U, D, L, R)会将你从当前位置传送到相邻的某个位置,因此在搜索过程中要处理传送器的跳转效果。
-
传送器的边界情况:
- 需要特别注意传送器可能会导致你跳出竞技场(即死亡),这种情况下我们不考虑这些位置。
解释:
-
初始化和反向BFS:
- 我们先找到出口
'O'的位置,将其加入队列并标记为可达。 - 从出口开始,进行BFS遍历,标记所有可以到达的格子为可达。
- 我们先找到出口
-
传送器的处理:
- 对于每个格子,如果是传送器,则按照它的类型(
U,D,L,R)跳转到对应的相邻格子,继续进行BFS。 - 传送器可能跳出边界,但这不算做有效的格子,因此跳出边界的情况会被忽略。
- 对于每个格子,如果是传送器,则按照它的类型(
-
危险位置的统计:
- 最后,遍历整个竞技场,对于所有不能到达出口的格子,增加“危险位置”的计数。
复杂度分析:
- 时间复杂度:BFS的时间复杂度是O(N * M),因为我们最多会访问每个格子一次。
- 空间复杂度:需要使用一个大小为N×M的数组来标记是否可达,因此空间复杂度为O(N * M)。
def solution(N, M, data):
def dfs(x, y, can_walk):
# 判断是否在迷宫内和是否已经访问过
if x < 0 or x >= N or y < 0 or y >= M:
return
if visited[x][y]:
return
visited[x][y] = True
can_walk[x][y] = True # 标记当前位置为可达
# 向上、下、左、右检查
if x - 1 >= 0 and (data[x - 1][y] == 'D' or data[x - 1][y] == '.'):
dfs(x - 1, y, can_walk)
if x + 1 < N and (data[x + 1][y] == 'U' or data[x + 1][y] == '.'):
dfs(x + 1, y, can_walk)
if y - 1 >= 0 and (data[x][y - 1] == 'R' or data[x][y - 1] == '.'):
dfs(x, y - 1, can_walk)
if y + 1 < M and (data[x][y + 1] == 'L' or data[x][y + 1] == '.'):
dfs(x, y + 1, can_walk)
# 找到出口
exit_x, exit_y = 0, 0
found_exit = False
for i in range(N):
for j in range(M):
if data[i][j] == 'O':
exit_x, exit_y = i, j
found_exit = True
break
if found_exit:
break
visited = [[False] * M for _ in range(N)]
can_walk = [[False] * M for _ in range(N)]
can_walk[exit_x][exit_y] = True # 标记出口为可达
dfs(exit_x, exit_y, can_walk)
# 统计无法到达出口的位置数量
unreachable_count = 0
for i in range(N):
for j in range(M):
if not can_walk[i][j]:
unreachable_count += 1
return unreachable_count
if __name__ == "__main__":
pattern = [
['.', '.', '.', '.', '.'],
['.', 'R', 'R', 'D', '.'],
['.', 'U', '.', 'D', 'R'],
['.', 'U', 'L', 'L', '.'],
['.', '.', '.', '.', 'O']
]
print(solution(5, 5, pattern) == 10)