1. 问题描述:
给定一个 n×n 的二维数组,如下所示:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。数据保证至少存在一条从左上角走到右下角的路径。
输入格式
第一行包含整数 n。接下来 n 行,每行包含 n 个整数 0 或 1,表示迷宫。
输出格式
输出从左上角到右下角的最短路线,如果答案不唯一,输出任意一条路径均可。按顺序,每行输出一个路径中经过的单元格的坐标,左上角坐标为 (0,0),右下角坐标为 (n−1,n−1)。
数据范围
0 ≤ n ≤ 1000
输入样例:
5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出样例:
0 0
1 0
2 0
2 1
2 2
2 3
2 4
3 4
4 4
来源:https://www.acwing.com/problem/content/1078/
2. 思路分析:
分析题目可以知道这道题目属于搜索类的题目,由于需要找到符合要求的任意一条从起点到终点的最短路径,所以我们可以使用宽搜来解决,宽搜有一个比较好的性质:当所有边权都相等的时候从起点开始搜索可以求解出起点到任意一个点的单元最短路径,这道题目其实有一个扩展:需要记录下最短路径的其中一个方案,其中一个比较常用的方法是使用二维的pre,其中pre[i][j] = (a,b)表示(i,j)可以由(a,b)走过来,我们可以从迷宫的最后一个位置开始宽搜来记录pre的值,最后就可以从起点开始递推输出最短路径方案。
3. 代码如下:
import collections
from typing import List
class Solution:
def bfs(self, n: int, x: int, y: int, g: List[List[int]], pre: List[List[tuple]]):
q = collections.deque([(x, y)])
pos = [[0, -1], [0, 1], [1, 0], [-1, 0]]
# 只要第一个元素不是-1就行
pre[x][y] = (0, 0)
while q:
x0, y0 = q.popleft()
for i in range(4):
a, b = x0 + pos[i][0], y0 + pos[i][1]
if a < 0 or a >= n or b < 0 or b >= n: continue
if g[a][b] == 1: continue
# (a, b)这个位置之前已经有位置走到那里了直接跳过
if pre[a][b][0] != -1: continue
q.append((a, b))
# 标记当前(a, b)是由(x0, y0)走过去的
pre[a][b] = (x0, y0)
def process(self):
n = int(input())
g = list()
for i in range(n):
g.append(list(map(int, input().split())))
# pre用来记录走到当前位置的上一个点是哪个点
pre = [[(-1, -1)] * (n + 10) for i in range(n + 10)]
# 从最后一个位置开始往前搜索, 这样可以从第一个位置往后求解最短路径的方案
self.bfs(n, n - 1, n - 1, g, pre)
# 从前往后找看是从哪个位置走进来的
x = y = 0
while True:
print(x, y)
# 走到了最后一个位置
if x == n - 1 and y == n - 1: break
x, y = pre[x][y][0], pre[x][y][1]
if __name__ == '__main__':
Solution().process()