棧和佇列的應用 迷宮問題(深度 廣度優先搜尋)

2022-05-02 18:09:06 字數 4474 閱讀 6125

給乙個二維列表,表示迷宮(0表示通道,1表示圍牆)。給出演算法,求一條走出迷宮的路徑。

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代表路,圖示如下:

應用棧解決迷宮問題,叫做深度優先搜尋(一條路走到黑),也叫做回溯法。

思路:從上乙個節點開始,任意找下乙個能走的點,當找不到能走的點時,退回上乙個點尋找是否有其他方向的點。

使用棧儲存當前路徑。後進先出,方便回退到上乙個點。

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 =

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:

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)

"""

總結演算法就是:建立乙個空棧,首先將入口位置進棧。當棧不空時迴圈:獲取棧頂元素,尋找下乙個可走的相鄰方塊,如果找不到可走的相鄰方塊,說明當前位置是死胡同,進行回溯(就是講當前位置出棧,看前面的點是否還有別的出路)

使用棧來解決迷宮問題,雖然實現起來比較簡單,但是它的路徑並不是最短的,很可能會繞遠,如果想走最短路徑可以使用佇列來做。

應用佇列解決迷宮問題,叫做廣度優先搜尋。

思路:從乙個節點開始,尋找所有接下來能繼續走的點,繼續不斷尋找,直到找到出口。

使用佇列儲存當前正在考慮的節點。整體過程如圖所示:

建立乙個空佇列,將起點1放入佇列,然後1只有一條路可走,因此1出列2進列,到3入列後由於有兩條路可走,3出列4、5入列;隨後先走4的方向4出列6入列,再5出列7入列,此時6、7在佇列中,6又有了兩個方向,此時6出列,8、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就繼續查詢

curnode = path[curnode[2]] # 這裡curnode[2]是當前節點的前一步節點的標識:path的下標,因此path[curnode[2]]拿到前一節點

realpath.reverse() # 將列表倒序,將前面生成的從後往前的列表變為從前往後

print(realpath)

def maze_path_queue(x1, y1, x2, y2): # (x1,y1)代表起點;(x2,y2)代表終點

"""用佇列實現迷宮問題——深度優先搜尋"""

queue = deque() # 建立佇列

path = # 儲存出隊節點

while len(queue) > 0: # 只有隊不空就一直迴圈

curnode = queue.pop() # 隊首節點出隊,並存為當前節點變數

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: # 如果有路可走

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)]

棧和佇列迷宮問題

define n 6 int maze n n 通過乙個數字來創造乙個6 6的迷宮,其中 0代表牆,1代表能夠走的路。這裡將陣列通過畫圖軟體畫出來,這裡紅色的1代表迷宮的入口,綠色的 1代表迷宮的出口。這個陣列所建立的迷宮是相對複雜的一種迷宮,首先這個迷宮是存在環的 這幾個1,如果你的迷宮函式只是用...

棧和佇列的迷宮問題

maze.h pragma once include include define n 6 static int maze n n typedef struct pos pos void mazeprint int mazegetpath pos entry,pos exit int mazeche...

解決迷宮問題, 棧和佇列

includeusing namespace std const int m 10,n 10 int mg m 1 n 1 const maxsize 200 struct qu maxsize int front 1,rear 1 隊首指標和隊尾指標 1 首先將 1,1 入隊 2 在佇列qu不為空...