广度优先搜索-迷宫问题
迷宫问题:定义一个矩阵:
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表示可以走的路,只能横着走或竖着走,不能斜着走,
要求编程序找出从左上角到右下角的最短路线。
【输入】一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
【输出】左上角到右下角的最短路径,格式如样例所示。
【输入样例】
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
【输出样例】
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
https://www.cnblogs.com/liuyankui163/p/8401183.html
思路:广度遍历是层次遍历,其实这道题问题的关键是如何找出路径,也就是如何存储
走过的路径是关键问题。因为是广度遍历,因此,如果能找到,那么肯定是
最短的路径,但是可能这条路径不是唯一的,所以找出来的路径,可能只是
其中一条最短路径而已,也许有多条最短路径。
这里是path[[row1,col1,index1],[row2,col2,index2],……],
row1,col1都是描述迷宫二维列表的位置,这个不难理解,关键是index1
的理解,是这道题的关键问题。index1表示该点是从path[]列表中的index1
位置走过来的。它记录走过的路径,也就是用path[]列表的下标值来记录每个
点是从哪里走过来的。
python算法实现:
1 from collections import deque 2 3 # 迷宫二维列表 4 maze = [] 5 # 对应迷宫的二维列表,0-为访问过,1-访问过 6 visited = [] 7 # 行数、列数 8 rows, cols = 0, 0 9 10 11 """ 12 path = 13 [[0, 0, -1], 14 [1, 0, 0], [2, 0, 1], [3, 0, 2], [2, 1, 2], [4, 0, 3], 15 [2, 2, 4], [4, 1, 5], [1, 2, 6], [2, 3, 6], [4, 2, 7], 16 [0, 2, 8], [2, 4, 9], [0, 3, 11], [1, 4, 12], [3, 4, 12], 17 [0, 4, 13], [4, 4, 15]] 18 第3列的值表示前面这个坐标的点是有path这个列表中第几个位置的顶走过来的。 19 比如[4, 4, 15],[4,4]这个点是由path[15],这个点[3, 4, 12]走过来的。 20 """ 21 22 23 def print_path(path): 24 # 从列表的最后一个点开始往前找 25 curNode = path[-1] 26 real_path = [] 27 # 遍历path,当第3列不是-1,就不是起点,不断遍历 28 while curNode[2] != -1: 29 # 把坐标点加入 30 real_path.append(curNode[0:2]) 31 # path[curNode[2]]表示curNode是由path[]列表中那个位置的点走过来的 32 curNode = path[curNode[2]] 33 # 把起点放进去 34 real_path.append(curNode[0:2]) 35 # 列表反转 36 real_path.reverse() 37 # 输出路径的长度 38 print(len(real_path)) 39 for i in real_path: 40 print(i) 41 42 43 def maze_path(): 44 global maze, visited, rows, cols 45 visited[0][0] = 1 46 # 创建一个双向队列 47 path_queue = deque() 48 # 从左上角出发,插入队列中 49 path_queue.append([0, 0, -1]) 50 # 路径列表 51 path = [] 52 while len(path_queue) > 0: 53 # 把队列中最左边的元素拿出来,并且移除队列 54 curNode = path_queue.popleft() 55 # 把该点加入路径列表 56 path.append(curNode) 57 # [0]-行,[1]-列,如果下面条件判断成立,说明走到右下角 58 if curNode[0] == rows-1 and curNode[1] == cols-1: 59 # 输出路径 60 print_path(path) 61 return True 62 # 分4个方向前进 63 # 上,不能访问列表越界,到达的下一个点没有访问过,并且该点的值是0,因为0表示可以走 64 if curNode[0] - 1 >= 0 and visited[curNode[0]-1][curNode[1]] == 0 and maze[curNode[0]-1][curNode[1]] == 0: 65 # 存储新点的值,len(path)-1表示该点是从path[]列表的哪个位置过来的 66 node = [curNode[0] - 1, curNode[1], len(path) - 1] 67 path_queue.append(node) 68 # 标记该点访问过了,下次不再访问 69 visited[curNode[0] - 1][curNode[1]] = 1 70 # 下 71 if curNode[0] + 1 < rows and visited[curNode[0]+1][curNode[1]] == 0 and maze[curNode[0]+1][curNode[1]] == 0: 72 node = [curNode[0] + 1, curNode[1], len(path) - 1] 73 path_queue.append(node) 74 visited[curNode[0] + 1][curNode[1]] = 1 75 # 左 76 if curNode[1] - 1 >= 0 and visited[curNode[0]][curNode[1]-1] == 0 and maze[curNode[0]][curNode[1]-1] == 0: 77 node = [curNode[0], curNode[1]-1, len(path) - 1] 78 path_queue.append(node) 79 visited[curNode[0]][curNode[1]-1] = 1 80 # 右 81 if curNode[1] + 1 < cols and visited[curNode[0]][curNode[1]+1] == 0 and maze[curNode[0]][curNode[1]+1] == 0: 82 node = [curNode[0], curNode[1]+1, len(path) - 1] 83 path_queue.append(node) 84 visited[curNode[0]][curNode[1]+1] = 1 85 else: 86 print("没有可以到达的路径!") 87 return False 88 89 90 def main(): 91 global maze, visited, rows, cols 92 rows, cols = map(int, input().split()) 93 for i in range(rows): 94 temp = list(map(int, input().split())) 95 maze.append(temp) 96 # [[0, 1, 0, 0, 0], [0, 1, 0, 1, 0], 97 # [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 0, 0, 1, 0]] 98 visited = [[0 for i in range(cols)] for i in range(rows)] 99 maze_path() 100 101 102 if __name__ == '__main__': 103 main()