1. 程式人生 > 實用技巧 >廣度優先搜尋-迷宮問題

廣度優先搜尋-迷宮問題

迷宮問題:定義一個矩陣:
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()