伴学笔记5

151 阅读5分钟

我好想逃却逃不掉

问题描述

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

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

——我好想逃。

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

你的任务是找出在迷宫的哪些位置,当玩家移动到此处时,无论接下来如何移动都无法再到达出口。


测试样例

样例1:

输入:N = 5, M = 5, data = [".....", ".RRD.", ".U.DR", ".ULL.", "....O"]
输出:10

样例2:

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

样例3:

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

代码提示

  1. 优化传送点的处理
    当前代码在处理传送点时,直接递归调用 can_reach_exit 函数。这可能会导致重复计算和栈溢出。可以考虑使用一个 visited 数组来记录已经访问过的位置,避免重复访问。
  2. 反向思考
    你可以从出口开始,反向标记所有可以到达出口的位置。这样,所有未被标记的位置就是无法到达出口的“危险位置”。
  3. 使用广度优先搜索(BFS)
    从出口开始,使用 BFS 来标记所有可以到达的位置。BFS 更适合处理这种需要遍历所有可能路径的问题。
  4. 处理边界情况
    确保在处理传送点时,不会传送到迷宫之外的位置。

代码解释

python def solution(N, M, data):

    # 构建迷宫矩阵

    maze = []

    for row in data:

        if isinstance

        (row, list):

            maze.append

            (row)

        else:

            maze.append

            (list(row))

  • 构建迷宫矩阵

    • maze 是一个二维列表,用于存储迷宫的地图。
    • data 是输入的迷宫数据,可能是一个二维列表或字符串列表。
    • 通过遍历 data,将每一行转换为列表并添加到 maze 中。

python

    # 方向映射

    directions = {

        'U': (-1, 0),  # 

        上

        'D': (1, 0),   # 

        下

        'L': (0, -1),  # 

        左

        'R': (0, 1)    # 

        右

    }

  • 方向映射

    • directions 是一个字典,用于映射传送点的方向到相应的坐标变化。
    • 'U' 表示向上移动,坐标变化为 (-1, 0)
    • 'D' 表示向下移动,坐标变化为 (1, 0)
    • 'L' 表示向左移动,坐标变化为 (0, -1)
    • 'R' 表示向右移动,坐标变化为 (0, 1)

python

def is_valid(x, y):

        return 0 <= x < N 

        and 0 <= y < M

  • 边界检查

    • is_valid 函数用于检查坐标 (x, y) 是否在迷宫的有效范围内。
    • 如果 x 和 y 都在 [0, N) 和 [0, M) 范围内,则返回 True,否则返回 False

python

    def can_reach_exit

    (start_x, start_y, 

    visited):

        # 越界检查

        if not is_valid

        (start_x, start_y)

        :

            return False

            

        # 如果已经访问过,说

        明形成了环

        if (start_x, 

        start_y) in 

        visited:

            return False

            

        # 到达出口

        if maze[start_x]

        [start_y] == 'O':

            return True

            

        # 记录当前位置为已访

        问

        visited.add

        ((start_x, 

        start_y))

        

        # 如果是传送点

        if maze[start_x]

        [start_y] in 

        directions:

            dx, dy = 

            directions

            [maze[start_x]

            [start_y]]

            next_x, 

            next_y = 

            start_x + dx, 

            start_y + dy

            return 

            can_reach_exit

            (next_x, 

            next_y, 

            visited)

        

        # 如果是普通点,尝试

        四个方向

        for dx, dy in 

        directions.values

        ():

            next_x, 

            next_y = 

            start_x + dx, 

            start_y + dy

            if is_valid

            (next_x, 

            next_y) and 

            can_reach_exit

            (next_x, 

            next_y, 

            visited.copy

            ()):

                return 

                True

                

        return False

  • 可达性检查

    • can_reach_exit 函数用于检查从 (start_x, start_y) 是否可以到达出口 'O'
    • 越界检查:如果当前位置越界,返回 False
    • 环检测:如果当前位置已经访问过,说明形成了环,返回 False
    • 到达出口:如果当前位置是出口 'O',返回 True
    • 记录访问:将当前位置标记为已访问。
    • 传送点处理:如果当前位置是传送点,计算传送后的位置,并递归检查传送后的位置。
    • 普通点处理:如果当前位置是普通点,尝试四个方向,递归检查每个方向的可达性。注意这里每次递归调用时都创建一个新的 visited 集合的副本,以避免状态共享问题。

python     # 统计无法到达出口的位置数

    量

    count = 0

    for i in range(N):

        for j in range(M):

            if maze[i][j] 

            != 'O':  # 不

            考虑出口本身

                if not 

                can_reach_

                exit(i, 

                j, set()):

                    count 

                    += 1

    

    return count

  • 统计无法到达出口的位置数量

    • 遍历迷宫中的每个位置 (i, j)
    • 如果当前位置不是出口 'O',则调用 can_reach_exit 函数检查是否可以到达出口。
    • 如果无法到达出口,则计数器 count 加 1。
    • 最后返回 count,即无法到达出口的位置数量。

python

if name == "main":

    # Add your test cases 

    here

    pattern = [

        [".",  ".", ".", 

        ".", "."],

        [".",  "R", "R", 

        "D", "."],

        [".", "U", ".", 

        "D", "R"],

        [".", "U", "L", 

        "L", "."],

        [".", ".", ".", ".

        ", "O"]

    ]

    print(solution(5, 5, 

    pattern) == 10)

  • 主函数

    • 定义了一个测试用例 pattern,并调用 solution 函数进行测试。
    • 打印结果,检查是否符合预期(预期结果为 10)。

总结

这段代码的主要功能是统计迷宫中无法到达出口的位置数量。通过递归检查每个位置是否可以到达出口,并使用 visited 集合来避免重复访问和环检测。代码的核心在于 can_reach_exit 函数,它通过递归和状态记录来判断可达性。