給一個二維列表,表示迷宮(0表示通道,1表示圍牆)。給出算法,求一條走出迷宮的路徑。python
maze = [ [1,1,1,1,1,1,1,1,1,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,0,0,1,1,0,0,1], [1,0,1,1,1,0,0,0,0,1], [1,0,0,0,1,0,0,0,0,1], [1,0,1,0,0,0,1,0,0,1], [1,0,1,1,1,0,1,1,0,1], [1,1,0,0,0,0,0,0,0,1], [1,1,1,1,1,1,1,1,1,1] ]
1表明牆,0表明路,圖示以下:算法
應用棧解決迷宮問題,叫作深度優先搜索(一條路走到黑),也叫作回溯法。app
思路:從上一個節點開始,任意找下一個能走的點,當找不到能走的點時,退回上一個點尋找是否有其餘方向的點。spa
使用棧存儲當前路徑。後進先出,方便回退到上一個點。blog
maze = [ [1,1,1,1,1,1,1,1,1,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,0,0,1,1,0,0,1], [1,0,1,1,1,0,0,0,0,1], [1,0,0,0,1,0,0,0,0,1], [1,0,1,0,0,0,1,0,0,1], [1,0,1,1,1,0,1,1,0,1], [1,1,0,0,0,0,0,0,0,1], [1,1,1,1,1,1,1,1,1,1] ] # 四個移動方向 dirs = [ lambda x,y: (x+1, y), # 下 lambda x,y: (x-1, y), # 上 lambda x,y: (x, y-1), # 左 lambda x,y: (x, y+1) # 右 ] def maze_path(x1, y1, x2, y2): # (x1,y1)表明起點;(x2,y2)表明終點 stack = [] stack.append((x1, y1)) while(len(stack)>0): curNode = stack[-1] # 當前的節點(棧頂) if curNode[0] ==x2 and curNode[1] == y2: # 判斷是否走到終點 # 走到終點,遍歷棧輸出路線 for p in stack: print(p) return True """搜索四個方向""" for dir in dirs: nextNode = dir(curNode[0], curNode[1]) # 若是下一個階段能走 if maze[nextNode[0]][nextNode[1]] == 0: stack.append(nextNode) # 將節點加入棧 maze[nextNode[0]][nextNode[1]] = 2 # 將走過的這個節點標記爲2表示已經走過了 break # 找到一個能走的點就再也不遍歷四個方向 else: # 一個都找不到,將該位置標記並該回退 maze[nextNode[0]][nextNode[1]] = 2 stack.pop() else: print("沒有路") return False maze_path(1,1,8,8) """ (1, 1) (2, 1) (3, 1) (4, 1) (5, 1) (5, 2) (5, 3) (6, 3) (6, 4) (6, 5) (7, 5) (8, 5) (8, 6) (8, 7) (8, 8) """
總結算法就是:建立一個空棧,首先將入口位置進棧。當棧不空時循環:獲取棧頂元素,尋找下一個可走的相鄰方塊,若是找不到可走的相鄰方塊,說明當前位置是死衚衕,進行回溯(就是講當前位置出棧,看前面的點是否還有別的出路)隊列
使用棧來解決迷宮問題,雖然實現起來比較簡單,可是它的路徑並非最短的,極可能會繞遠,若是想走最短路徑可使用隊列來作。utf-8
應用隊列解決迷宮問題,叫作廣度優先搜索。io
思路:從一個節點開始,尋找全部接下來能繼續走的點,繼續不斷尋找,直到找到出口。class
使用隊列存儲當前正在考慮的節點。總體過程如圖所示:import
建立一個空隊列,將起點1放入隊列,而後1只有一條路可走,所以1出列2進列,到3入列後因爲有兩條路可走,3出列四、5入列;隨後先走4的方向4出列6入列,再5出列7入列,此時六、7在隊列中,6又有了兩個方向,此時6出列,八、9入列,此時隊列中爲7\8\9,以此規律依次類推,直到找到出口。
隊列中存的再也不是路徑,而是如今考慮的路,分岔的中端。所以輸出路徑會比較麻煩。
須要一個額外的列表記錄哪一個點讓哪一個點加入進來,從終點往前推導得出迷宮路徑。
# -*- coding:utf-8 -*- __author__ = 'Qiushi Huang' from collections import deque # 引入隊列 maze = [ [1,1,1,1,1,1,1,1,1,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,0,0,1,1,0,0,1], [1,0,1,1,1,0,0,0,0,1], [1,0,0,0,1,0,0,0,0,1], [1,0,1,0,0,0,1,0,0,1], [1,0,1,1,1,0,1,1,0,1], [1,1,0,0,0,0,0,0,0,1], [1,1,1,1,1,1,1,1,1,1] ] # 四個移動方向 dirs = [ lambda x,y: (x+1, y), # 下 lambda x,y: (x-1, y), # 上 lambda x,y: (x, y-1), # 左 lambda x,y: (x, y+1) # 右 ] def print_r(path): """打印路徑""" curNode = path[-1] # 最後一個節點 realpath = [] # 出去的路徑 while curNode[2] != -1: # 判斷最後一個節點的標記是否爲-1,若是是-1說明是起始點,若是不是-1就繼續查找 realpath.append(curNode[0:2]) # 拿到並添加節點x,y座標信息 curNode = path[curNode[2]] # 這裏curNode[2]是當前節點的前一步節點的標識:path的下標,所以path[curNode[2]]拿到前一節點 realpath.append(curNode[0:2]) # 在這裏curNode[2] == -1,是迷宮起點,將座標信息加入路徑 realpath.reverse() # 將列表倒序,將前面生成的從後往前的列表變爲從前日後 print(realpath) def maze_path_queue(x1, y1, x2, y2): # (x1,y1)表明起點;(x2,y2)表明終點 """用隊列實現迷宮問題——深度優先搜索""" queue = deque() # 建立隊列 queue.append((x1, y1, -1)) # 加入起點,第三個參數是記錄時誰讓它來的,這裏起始點設置爲-1 path = [] # 保存出隊節點 while len(queue) > 0: # 只有隊不空就一直循環 curNode = queue.pop() # 隊首節點出隊,並存爲當前節點變量 path.append(curNode) # 添加到path列表 if curNode[0] == x2 and curNode[1] == y2: # 判斷是否找到終點 print_r(path) # 若是到達終點,打印路徑 return True for dir in dirs: # 搜索四個方向 nextNode = dir(curNode[0], curNode[1]) # curNode[0],curNode[1]分別是當前節點x、y if maze[nextNode[0]][nextNode[1]] == 0: # 若是有路可走 queue.append((nextNode[0], nextNode[1], len(path) - 1)) # 後續節點進隊,標記誰讓它來的:path最後一個元素的下標 maze[nextNode[0]][nextNode[1]] = 2 # 設置爲2,標記爲已經走過 else: # 若是隊列爲空(當前節點到了死路,節點刪除沒有新節點加入),沒有路 print("沒有路") return False maze_path_queue(1,1,8,8) # [(1, 1), (1, 2), (2, 2), (3, 2), (3, 1), (4, 1), (5, 1), (5, 2), (5, 3), (6, 3), (6, 4), (6, 5), (5, 5), (5, 6), (5, 7), (5, 8), (6, 8), (7, 8), (8, 8)]