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

176 阅读5分钟

问题描述

曾经的我不过是一介草民,混迹市井,默默无名。直到我被罗马的士兵从家乡捉走丢进竞技场……

对手出现了,我架紧盾牌想要防御,只觉得巨大的冲击力有如一面城墙冲涌而来,击碎了我的盾牌,我两眼发昏,沉重的身躯轰然倒地。

——我好想逃。

但罗马最大的竞技场,哪有这么容易逃得掉。工程师们早就在地上装了传送机关,虽不会伤人,却会将站在上面的人传到它指向的位置。若是几个传送机关围成一个环,不小心踩在上面的人就会被一圈圈地反复传送……想到这里,我不由得打了个寒颤。必须避开这些危险的地方!

在一个 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)来从出口位置反向查找哪些格子是无法到达的。

思路:

  1. 反向搜索

    • 从出口位置 O 开始进行广度优先搜索(BFS)或者深度优先搜索(DFS),标记所有能够到达出口的位置。
    • 然后遍历整个竞技场,将不能到达出口的格子视为“危险位置”。
  2. 传送器的处理

    • 传送器(U, D, L, R)会将你从当前位置传送到相邻的某个位置,因此在搜索过程中要处理传送器的跳转效果。
  3. 传送器的边界情况

    • 需要特别注意传送器可能会导致你跳出竞技场(即死亡),这种情况下我们不考虑这些位置。

解释:

  1. 初始化和反向BFS

    • 我们先找到出口 'O' 的位置,将其加入队列并标记为可达。
    • 从出口开始,进行BFS遍历,标记所有可以到达的格子为可达。
  2. 传送器的处理

    • 对于每个格子,如果是传送器,则按照它的类型(U, D, L, R)跳转到对应的相邻格子,继续进行BFS。
    • 传送器可能跳出边界,但这不算做有效的格子,因此跳出边界的情况会被忽略。
  3. 危险位置的统计

    • 最后,遍历整个竞技场,对于所有不能到达出口的格子,增加“危险位置”的计数。

复杂度分析:

  • 时间复杂度: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)