網站首頁 編程語言 正文
前言
在迷宮問題中,給定入口和出口,要求找到路徑。本文將討論三種求解方法,遞歸求解、回溯求解和隊列求解。
在介紹具體算法之前,先考慮將迷宮數字化。這里將迷宮用一個二維的list存儲(即list嵌套在list里),將不可到達的位置用1表示,可到達的位置用0表示,并將已經到過的位置用2表示。
遞歸求解
遞歸求解的基本思路是:
- 每個時刻總有一個當前位置,開始時這個位置是迷宮人口。
- 如果當前位置就是出口,問題已解決。
- 否則,如果從當前位置己無路可走,當前的探查失敗,回退一步。
- 取一個可行相鄰位置用同樣方式探查,如果從那里可以找到通往出口的路徑,那么從當前位置到出口的路徑也就找到了。
在整個計算開始時,把迷宮的人口(序對)作為檢查的當前位置,算法過程就是:
- mark當前位置。
- 檢查當前位置是否為出口,如果是則成功結束。
- 逐個檢查當前位置的四鄰是否可以通達出口(遞歸調用自身)。
- 如果對四鄰的探索都失敗,報告失敗。
dirs=[(0,1),(1,0),(0,-1),(-1,0)] #當前位置四個方向的偏移量 path=[] #存找到的路徑 def mark(maze,pos): #給迷宮maze的位置pos標"2"表示“倒過了” maze[pos[0]][pos[1]]=2 def passable(maze,pos): #檢查迷宮maze的位置pos是否可通行 return maze[pos[0]][pos[1]]==0 def find_path(maze,pos,end): mark(maze,pos) if pos==end: print(pos,end=" ") #已到達出口,輸出這個位置。成功結束 path.append(pos) return True for i in range(4): #否則按四個方向順序檢查 nextp=pos[0]+dirs[i][0],pos[1]+dirs[i][1] #考慮下一個可能方向 if passable(maze,nextp): #不可行的相鄰位置不管 if find_path(maze,nextp,end):#如果從nextp可達出口,輸出這個位置,成功結束 print(pos,end=" ") path.append(pos) return True return False def see_path(maze,path): #使尋找到的路徑可視化 for i,p in enumerate(path): if i==0: maze[p[0]][p[1]] ="E" elif i==len(path)-1: maze[p[0]][p[1]]="S" else: maze[p[0]][p[1]] =3 print("\n") for r in maze: for c in r: if c==3: print('\033[0;31m'+"*"+" "+'\033[0m',end="") elif c=="S" or c=="E": print('\033[0;34m'+c+" " + '\033[0m', end="") elif c==2: print('\033[0;32m'+"#"+" "+'\033[0m',end="") elif c==1: print('\033[0;;40m'+" "*2+'\033[0m',end="") else: print(" "*2,end="") print() if __name__ == '__main__': maze=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1],\ [1,0,0,0,1,1,0,0,0,1,0,0,0,1],\ [1,0,1,0,0,0,0,1,0,1,0,1,0,1],\ [1,0,1,0,1,1,1,1,0,1,0,1,0,1],\ [1,0,1,0,0,0,0,0,0,1,1,1,0,1],\ [1,0,1,1,1,1,1,1,1,1,0,0,0,1],\ [1,0,1,0,0,0,0,0,0,0,0,1,0,1],\ [1,0,0,0,1,1,1,0,1,0,1,1,0,1],\ [1,0,1,0,1,0,1,0,1,0,1,0,0,1],\ [1,0,1,0,1,0,1,0,1,1,1,1,0,1],\ [1,0,1,0,0,0,1,0,0,1,0,0,0,1],\ [1,1,1,1,1,1,1,1,1,1,1,1,1,1]] start=(1,1) end=(10,12) find_path(maze,start,end) see_path(maze,path)
代碼中see_path函數可以在控制臺直觀打印出找到的路徑,打印結果如下:
S是入口位置 ,E是出口位置,*代表找到的路徑,#代表探索過的路徑。
回溯求解
在回溯解法中,主要是用棧來存儲可以探索的位置。利用棧后進先出的特點,在一條分路上探索失敗時,回到最近一次存儲的可探索位置。這是一種深度優先搜索的方法。
def maze_solver(maze,start,end): if start==end: print(start) return st=SStack() mark(maze,start) st.push((start,0)) #入口和方向0的序對入棧 while not st.is_empty(): #走不通時回退 pos,nxt=st.pop() #取棧頂及其檢查方向 for i in range(nxt,4): #依次檢查未檢查方向,算出下一位置 nextp = pos[0] + dirs[i][0], pos[1] + dirs[i][1] if nextp==end: print_path(end,pos,st) #到達出口,打印位置 return if passable(maze,nextp): #遇到未探索的新位置 st.push((pos,i+1)) #原位置和下一方向入棧 mark(maze,nextp) st.push((nextp,0)) #新位置入棧 break #退出內層循環,下次迭代將以新棧頂作為當前位置繼續 print("找不到路徑")
隊列求解
隊列求解算法中,以隊列存儲可以探索的位置。利用隊列先進先出的特點,實現在每個分支上同時進行搜索路徑,直到找到出口。這是一種廣度優先搜索的方法。
def maze_solver_queue(maze,start,end): path.append(start) if start==end: print("找到路徑") return qu=SQueue() mark(maze,start) qu.enqueue(start) #start位置入隊 while not qu.is_empty(): #還有候選位置 pos=qu.dequeue() #取出下一位置 for i in range(4): #檢查每個方向 nextp = pos[0] + dirs[i][0], pos[1] + dirs[i][1] if passable(maze,nextp): #找到新的探索方向 if nextp==end: #是出口,成功 print("找到路徑") path.append(end) return mark(maze,nextp) qu.enqueue(nextp) #新位置入隊 path.append(nextp) print("未找到路徑")
但隊列求解方法,不能直接得出找到的具體路徑,要得到找到的路徑還需要其他存儲結構(如鏈表)。
總結
原文鏈接:https://blog.csdn.net/qq_29681777/article/details/83719680
相關推薦
- 2022-03-07 android?studio實驗:?UI設計?ListView及事件響應_Android
- 2021-12-09 JQuery選擇器詳解_jquery
- 2022-12-01 SQL?Server主鍵與外鍵設置以及相關理解_MsSql
- 2023-07-04 注冊npm上傳包報This operation requires a one-time passwo
- 2022-08-14 使用Python去除字符串中某個字符的多種實現方式比較_python
- 2022-06-09 FreeRTOS實時操作系統的多優先級實現_操作系統
- 2022-12-31 Mobx實現React?應用的狀態管理詳解_React
- 2022-09-29 React事件監聽和State狀態修改方式_React
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支