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

85 阅读4分钟

一、 问题描述

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

对手出现了,我紧握盾牌准备防御,却只感觉到一股巨大的冲击力,如同一面城墙撞击而来,瞬间击碎了我的盾牌。我眼前一片昏黑,沉重的身躯轰然倒地。

——我好想逃。

但在罗马最大的竞技场中,逃脱绝非易事。工程师们早已在地面装了传送机关,虽然不会造成伤害,但站上这些机关会被传送到指定位置。如果多个传送器围成一个环,站在上面的人会被反复传送,根本无法逃脱。

想到这些,我不禁打了个寒颤。必须避开这些危险区域!

在一个 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)