一、 问题描述
曾经,我不过是一介草民,混迹市井,默默无名。直到一天,我被罗马士兵从家乡捉走,丢进了竞技场……
对手出现了,我紧握盾牌准备防御,却只感觉到一股巨大的冲击力,如同一面城墙撞击而来,瞬间击碎了我的盾牌。我眼前一片昏黑,沉重的身躯轰然倒地。
——我好想逃。
但在罗马最大的竞技场中,逃脱绝非易事。工程师们早已在地面装了传送机关,虽然不会造成伤害,但站上这些机关会被传送到指定位置。如果多个传送器围成一个环,站在上面的人会被反复传送,根本无法逃脱。
想到这些,我不禁打了个寒颤。必须避开这些危险区域!
在一个 N × M 的竞技场迷宫中,你的任务是找出所有“危险位置”的数量。“危险位置”定义为:如果站在该位置上,无论如何移动,都无法到达出口。
竞技场中包含以下几种元素:
· .:普通地板,可以自由移动。
· O:出口。
· U:向上的传送器,踩上去会被强制传送到上方的格子。
· D:向下的传送器,踩上去会被强制传送到下方的格子。
· L:向左的传送器,踩上去会被强制传送到左方的格子。
· R:向右的传送器,踩上去会被强制传送到右方的格子。
如果传送器将你传送出竞技场之外,则算作死亡。
二、 输入说明
· N:一个整数,表示竞技场的行数。
· M:一个整数,表示竞技场的列数。
· data:一个字符二维数组,表示竞技场的地图。数组大小为 N × M,其中 1 ≤ N, M ≤ 100。
三、 输出说明
输出一个整数,表示“危险位置”的数量。
四、 测试样例
( 1 ) 样例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 ) 样例2:
输入:
N = 4, M = 4, data = [
[".", "R", ".", "O"],
["U", ".", "L", "."],
[".", "D", ".", "."],
[".", ".", "R", "D"]
]
输出:
2
( 3 ) 样例3:
输入:
N = 3, M = 3, data = [
[".", "U", "O"],
["L", ".", "R"],
["D", ".", "."]
]
输出:8
五、 解题思路
( 1 ) 寻找迷宫出口: 首先,遍历整个迷宫,找到表示出口 O 的坐标 (exitX, exitY)。找到出口非常重要,因为所有路径的可达性是基于从出口向外扩展的探索。
( 2 ) 深度优先搜索 (DFS) 标记可达路径: 从出口出发,使用深度优先搜索 (DFS) 遍历所有可以到达的位置。每个位置只能访问一次,因此需要记录访问状态。每个位置的访问判断依据其相邻格子的类型:
o . 表示普通地板,可以自由移动。
o U 只能向上移动。
o D 只能向下移动。
o L 只能向左移动。
o R 只能向右移动。
( 3 ) 标记可达位置: 使用一个 canWalk 数组标记哪些位置是从出口可以到达的。初始化时,所有位置默认不可达,除了出口位置。每访问一个符合条件的格子,就将其标记为可达。
( 4 ) 统计不可达位置: 在完成 DFS 遍历后,再次遍历整个迷宫,统计 canWalk 数组中值为 False 的格子数量,得到不可达位置的数量。
六、 复杂度分析
( 1 ) 时间复杂度:
o 遍历迷宫寻找出口:O(N * M)。
o 深度优先搜索 (DFS):最多访问每个格子一次,时间复杂度为 O(N * M)。
o 统计不可达位置:O(N * M)。 总计时间复杂度为 O(N * M)。
( 2 ) 空间复杂度:
o 需要额外的 visited 和 canWalk 数组,大小为 N * M。
o 递归调用栈的深度最大为迷宫大小,空间复杂度为 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)