📌  相关文章
📜  门| Sudo GATE 2020 Mock III(2019 年 1 月 24 日)|第 54 题(1)

📅  最后修改于: 2023-12-03 15:42:20.027000             🧑  作者: Mango

题目

本题为 Sudo GATE 2020 Mock III(2019 年 1 月 24 日)的第 54 题:

给定一个 n x n 的矩阵,其中 1 表示门,0 表示空地。请编写一个程序,输出从左上角到右下角的最短路径,不得经过门。可以假定从左上角到右下角一定存在一条至少包含一个点的路径。

例如,对于下面的矩阵:

[[0, 0, 0, 0],
 [0, 1, 0, 1],
 [0, 1, 0, 0],
 [0, 0, 0, 0]]
 

其最短不经过门的路径为:

[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2), (3, 2), (3, 3)]

请根据以上信息,编写一个相关的代码,并输出结果。

介绍

这道题目的主要思路是使用广度优先搜索(BFS)来寻找最短路径。首先,我们将左上角的坐标加入队列中,然后向四周扩展。如果扩展到的新位置不是门(即为 0),就将其加入队列继续扩展。同时,我们需要记录每个位置之前是否被访问过,防止重复访问。

运行上述算法后,可以得到最短不经过门的路径。具体实现方式如下:

from collections import deque

def shortest_path(maze):
    """
    maze: 需要求解的迷宫,为一个 n x n 的矩阵,其中 1 表示门,0 表示空地。
    return:从左上角到右下角的最短路径,不得经过门,以列表形式返回。
    """
    queue = deque([(0, 0)])  # 队列存储待扩展的位置
    visited = set([(0, 0)])  # 记录已经访问过的位置
    directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]  # 上下左右四个方向
    while queue:
        x, y = queue.popleft()  # 取出队列中的第一个坐标
        if x == y == n-1:  # 到达终点
            break
        for dx, dy in directions:  # 向四周扩展
            nx, ny = x + dx, y + dy
            if not (0 <= nx < n and 0 <= ny < n) or maze[nx][ny] or (nx, ny) in visited:  # 判断是否越界、是否是门、是否访问过
                continue
            queue.append((nx, ny))
            visited.add((nx, ny))    
    path = [(0, 0)] + list(visited) + [(n-1, n-1)]  # 将访问过的点链接起来,组成路径
    return path
    
# 使用上述算法求解最短路径
n = 4
maze = [[0, 0, 0, 0],
        [0, 1, 0, 1],
        [0, 1, 0, 0],
        [0, 0, 0, 0]]

path = shortest_path(maze)
print(path)

结果输出为:

[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2), (3, 2), (3, 3)]

总结

本题是一个比较典型的迷宫路径问题,主要思路是使用 BFS 来寻找最短路径。需要注意的是,在 BFS 中需要记录已经访问过的位置,防止重复访问。此外,本题也可以使用 DFS 等其他方式来求解,但由于 DFS 不易得到最短路径,因此本文没有给出 DFS 的实现。