1. 程式人生 > >對於DFS,BFS,A*與IDA*等尋路演算法的總結跟感悟

對於DFS,BFS,A*與IDA*等尋路演算法的總結跟感悟

本人大一,今年2017最後一天,準備做點這學期學的演算法一點總結,當做複習吧。

 一週前看見了貪吃蛇AI演算法,受到震撼於是就把以前的win32貪吃蛇加了個AI實現,讓我這個渣渣寫了好幾天才完工再見,終於能吃完全屏了,雖然離自己看的那個貪吃蛇AI的gif還有些距離emmmm,貪吃蛇AI不可避免的用到了尋路演算法,所以今天當做複習總結提一提,

   不說了,進入正題吧,常見的搜尋有深度優先搜尋,廣度優先搜尋,迭代加深搜尋,雙向廣度優先先搜尋,A*搜尋,IDA*搜尋等,這些搜尋分為盲目式搜尋啟發式搜尋

何為盲目?何為啟發?。舉個例子,加入你在學校操場,老師叫你去國旗那集合,你會怎麼走?

假設你是瞎子,你看不到周圍,那如果你運氣差,那你可能需要把整個操場走完才能找到國旗。這便是盲目式搜尋,即使知道目標地點,你可能也要走完整個地圖。

假設你眼睛沒問題,你看得到國旗,那我們只需要向著國旗的方向走就行了,我們不會傻到往國旗相反反向走,那沒有意義。

這種有目的的走法,便被稱為啟發式的。

而今天要提到的深度優先跟廣度優先,便是盲目式搜尋,而A*跟IDA*,便是啟發式搜尋。

盲目式搜尋

DFS

深度優先(DFS)正如他的名字,每次先往深度走,如果此路走到底都沒找到,退回到原點,換另一條路找,如果走到底還是沒找到,繼續換一條路,直到全部路走完。

DFS由於每次向深處搜尋然後返回,很容易就讓人想到用棧實現,而系統本來就有提供棧,即用遞迴實現。DFS函式裡,一般都是在一個迴圈呼叫自己完成遞迴過程,如果用迷宮比喻的話,每次遞迴返回便是走完一條路,而這個迴圈便是有多少條路,這樣每個路口都會實現同樣的操作,便能把整個迷宮搜尋完。因其每次會返回的特點DFS在列舉演算法裡也稱為回溯法,DFS走的路徑被稱為解答樹。下面的圖中,只有(1,3,0,2)跟(2,0,3,1)是到達了目標,其他都是死路

BFS

廣度優先(BFS)是,每次先搜尋周圍,先把原點方圓1m找完,如果找不到,就找再向外擴充套件1m,如果找不到,就再向外擴充套件1m,每次擴大自己的圈子,直到整個地圖走完。很像傳染病,從開始一個點慢慢傳染到整個地區

BFS則是用佇列實現跟迴圈實現,每次把當前節點周圍的節點加入佇列,然後pop出佇列,不斷迴圈,直到佇列為空。一種用遞迴一種用迴圈,很明顯,在時間上,深度優先搜尋一般要比廣度優先搜尋慢,但廣度優先搜尋需要大量的空間。所以說這兩種演算法各有優缺點。

在說啟發式搜尋之前,先說說尋路演算法

尋路演算法

一般要到終點,我們會關注兩件事,要走多遠以及這條路要怎麼走。然後為了不重複走過的路,我們還需要標記這條路已經走過,即判重

走多遠,即是最少步數。如果用DFS來說,即是深度,用BFS來說,便是向外擴充套件了多少米(其實也是深度)。

那怎麼記錄路徑呢?辦法是每個節點加個指向前一個節點的指標,每一步記錄前一步,便能記錄整條路徑。DFS不用說,就是解答樹的一個分支,而BFS則是會形成一顆BFS樹


但是這樣得出來的路徑是從終點到起點的路徑,這裡便需要從終點開始用遞迴打印出來,便能列印起點到終點的路徑。

DFS以解答樹遍歷,不會重複,無需判重,但如果是用DFS進行回溯法列舉,則可能需要判重

BFS判重的方法可以用bool陣列,然後true表示走過節點,false表示沒走過的節點,如果是比較複雜的狀態等,則可能需要hash了(當《演算法導論》中DFS跟BFS用的都是OPEN跟CLOSE表)

啟發式搜尋

啟發式搜尋的好壞基本都取決於評估函式。

IDA*演算法

要說IDA*演算法,就先說迭代加深搜尋吧。本來不打算說的,先說一個DFS的一個問題,如果現在的路的深度沒有上限,即沒有底,那麼直接DFS就回不來了。。。所以就有了迭代加深搜尋,即每次給DFS加個記錄深度的(或者說解答樹的層數)引數d,每次走到相應的深度就返回。由於深度d是慢慢遞增的,這樣的得出了的答案毫無疑問是最小深度(即少步數),但是缺點很明顯,重複遍歷解答樹上層多次,造成巨大浪費。而IDA*則多了評估函式(或者說剪枝),每次預估如果這條路如果繼續下去也無法到達終點,則放棄這條路(剪枝的一種,即最優性剪枝)。IDA*原理實現起來簡單,非常方便,但難的地方是評估函式的編寫,足夠好的評估函式可以避免走更多的不歸路,如果評估函式太差或者沒有評估函式,那會退化到迭代加深搜尋那種浪費程度。如果想要學IDA*演算法,我推薦演算法競賽入門經典中的暴力列舉法—迭代加深搜尋一章。

A*演算法

A*演算法我想很多人都聽說過,這是AI演算法應用最廣泛的演算法之一,經常用到遊戲裡尋找最短路的演算法裡。如果說IDA*演算法是改進DFS演算法來的,A*演算法便是BFS演算法的升級版。A*演算法跟BFS一樣,擴充套件周圍的幾個點,但是A*會評估這幾個點哪個到終點比較近,然後選擇近的走,然後繼續評估,又選擇近的走,直到走到終點。

        如何每次保證選擇到的是最近的呢?這裡就需要用到了。建立一個最小堆,每次取最上面的一個。而比較大小的標準是通過評估值F的大小,以最短路徑來說,每次會選F值最小的。對於節點n有這樣的定義,f(n) = g(n) + h(n), 其中g(n)是到節點n已經花費的代價,h是到g(n)的估計代價,也可以認為是最少代價。在最短路徑中h函式可以用歐幾里得距離,或者曼哈頓距離來判斷,歐幾里得距離通俗點說即兩點間長度。曼哈頓距離就是x軸距離+y軸距離。至於g(n),可以設定走一步代價為1(當然你想設定成8,9,10之類的隨便,只是一個度量),g值跟Dijkstra的鬆弛一樣,需要更新,每次找到一個節點可以讓它更新為更小的,就更新g值跟f值(h值不用更新,因為對於每個點的h值都是確定的)。

         A*演算法跟BFS一樣,需要用father來記錄上一個節點,從而實現遍歷最短路徑。至於判重操作,A*的判重是通過兩個表(或許該說是兩個堆)判重的,一般叫做open表跟close表(當然BFS也可以通過open跟close佇列實現判重),close表存放已經走過的點,open表中是還沒走的節點,每次從open取出f值最小的作為當前節,然後擴充套件當前節點周圍的點push進open表,然後pop並把當前點放到close表中,然後繼續重複以上操作,每次從open取出f值最小的作為當前節.......如果此條最近的路不通,如遇到牆之類的,A*便選擇第二短的路(當然第一第二可能一樣短),(這裡最近的路是如操場無障礙那種,那我們走直線距離肯定最近,但是如果我們走近發現前面有一堵牆,此路不通,我們就得退回去試試其他路,A*會馬上跳轉到剛才第二近的路進行下一步擴充套件),如果還不通,就選擇第三短的路。。。直到open表中出現了目標節點,則表示已經找到最短路,退出迴圈,如果open表為空,則表示不存在到達目標的路徑。

總結起來:A*演算法=BFS的擴充套件方式+預估函式的+Dijkstra的鬆弛方式+堆的使用+open跟close表的判重+father記錄路徑。

關於A*演算法,這是我看過的一個寫的不錯的文章http://blog.csdn.net/u012234115/article/details/47152137,可以當做參考。

總結,DFS在搜尋中使用返回,IDA*是DFS的延伸還是用到棧,BFS使用佇列擴充套件,A*使用來取出評估最好的值,理解這三個資料結構,才能較好理解這三種演算法,無非就是,如果這點符合條件的就擴充套件,然後用不同的資料結構擴充套件,前兩者不管資料如何,看到就放入,後者用堆,實現大小排序,可以選擇更好的路徑。 幾種搜尋不同的條件下返回,DFS是走到底,A*跟BFS是佇列為空,IDA*是到達目標深度或者剪枝

幾種搜尋演算法就說到這,暫時想到這麼多,由於本人知識有限,如果有什麼錯誤,望各位大佬糾正

相關推薦

對於DFSBFSA*IDA*演算法總結感悟

本人大一,今年2017最後一天,準備做點這學期學的演算法一點總結,當做複習吧。 一週前看見了貪吃蛇AI演算法,受到震撼於是就把以前的win32貪吃蛇加了個AI實現,讓我這個渣渣寫了好幾天才完工,終於能吃完全屏了,雖然離自己看的那個貪吃蛇AI的gif還有些距離emmmm,貪吃蛇

[uvalive 7263] Today Is a Rainy Day(暴力BFSdp)

預處理 ini pen sta 現在 修改 ace printf main 題目鏈接:https://vjudge.net/problem/UVALive-7263 題意:給兩個字符串a,b,只包含1~6的數字,現在允許兩種操作:1、修改某一位數字,2、修改整個串的某個數字

判斷圖連通的三種方法——dfsbfs並查集

題目 pan closed 節點 out esp cli div find Description 如果無向圖G每對頂點v和w都有從v到w的路徑,那麽稱無向圖G是連通的。現在給定一張無向圖,判斷它是否是連通的。 Input 第一行有2個整數n和m(0 <

洛谷P1141 01迷宮(dfsbfs回溯更新問題記憶化或者並查集根結點)

ace else 賦值 www int iomanip 什麽 使用 algorithm 題目鏈接:https://www.luogu.org/problemnew/show/P1141 題目相當於求聯通塊,這個比較簡單,但加上了m次詢問後就是難點所在,很容易超時。 一定

圖形結構:遍歷模型分治法動態規劃回溯法BFSDFS

圖形結構,是樹形結構的擴充套件。 我們在回溯法裡面瞭解到幾種結構:二叉樹,排列樹,完全n叉樹,這幾種解空間型別,都可以直接使用回溯法的框架解決。 二叉樹,排列樹,完全n叉樹,都可以看成x叉樹的變形,而圖形結構就是x叉樹。 在此之前,我們先明白一點:一顆二叉樹是什麼,他是某一顆二叉

圖的鄰接表的遍歷(DFS(遞迴非遞迴)BFS拓撲排序)

要求:對有向圖進行DFS(深度優先遍歷)、BFS(廣度優先遍歷)、拓撲排序。寫出深度優先遍歷的遞迴和非遞迴演算法。 程式碼如下: 在此非常感謝crazy_27的評論,給我指出錯誤。 #include <stdio.h> #include <stdlib.h

迷宮問題 最短路徑 怎樣記錄路徑的總結(dijikstrabfsfloyd優先佇列)

這次集訓做了幾個關於記錄路徑的問題,大體基於迪傑斯特拉(dijikstra)和弗洛伊德(floyd)演算法還有BFS廣搜。 記錄前驅要比記錄後驅更保險,因為從終點往起點追溯很容易,而從起點往後追溯有很

PAT DFSBFSDijkstra 題號

遇到 最短路 短路徑 結果 時間 清晰 直接 今天 我們 為什麽要分類刷題: 因為刷?道算法題需要花?兩個?時甚?半天,平時我們還要上課做別的事情,你在?段時間內刷算法如果只按照順序,可能今天遇到了?道最短路徑的題?,弄了半天好不容易看懂了別?的代碼,以為??懂了,結果?

勝利大逃亡bfs廣度優先搜索

地圖 cin 策略 mark 時間 -1 bfs 一個 bool 題目描述: Ignatius被魔王抓走了,有一天魔王出差去了,這可是Ignatius逃亡的好機會.魔王住在一個城堡裏,城堡是一個A*B*C的立方體,可以被表示成A個B*C的矩陣,剛開始Ignatius被關在(

A*IDA*的奇妙之旅

因為A*卡了一天QAQ 那麼,A*是什麼呢? A* A*是對於bfs的優化,啟發式搜尋。 例如下圖: 不錯,在這張圖上,小人去找電腦,用bfs的話: 黃色就是bfs的搜尋範圍。。。不要問我為什麼選黃色 Dij不會打全稱 那麼,A*是怎樣的呢? 沒看出區別?我都看不出區別 那麼,

二、基本演算法DFSBFSA*

         圖中節點的遍歷和搜尋是老生常談的話題,這裡藉由python的networkx庫,複習一下之前的BFS和DFS,並對A*做一些理解。  1.BFS 廣度優先搜尋          其基本思想是優先從當前節點的鄰居節點開始搜尋,如果搜尋不到,再搜尋鄰居的鄰居。

天神降臨大家過來膜拜吧! FLASH AS 3.0 A星(A*, A star) 演算法--史上最快,極限優化挑戰!

天神降臨,大家過來膜拜吧!  oh yeah! 轉載請宣告出處,例子程式碼可以免費隨意使用,但請保留或註明作者資訊.  這裡的演算法說是終極優化, 我挑戰了一下, 最終結果比較他快三倍, 我站在高高處,藐視了 一下作者. 優化思路:       

HDU 1043 Eight八數碼解題思路(bfs+hash 打表 IDA*

中間 節點 sca 技巧 length div clu 鏈接 output 題目鏈接 https://vjudge.net/problem/HDU-1043 經典的八數碼問題,學過算法的老哥都會拿它練搜索 題意: 給出每行一組的數據,每組數據代表3*3的八數碼表,要求程序復

A*演算法的優化改進

提要通過對上一篇A*尋路演算法的學習,我們對A*尋路應該有一定的瞭解了,但實際應用中,需要對演算法進行一些改進和優化。 Iterative Deepening Depth-first search- 迭代深化深度優先搜尋在深度優先搜尋中一個比較坑爹情形就是在搜尋樹的一枝上沒有

A*演算法它的速度

如果你是一個遊戲開發者,或者開發過一些關於人工智慧的遊戲,你一定知道A*演算法,如果沒有接觸過此類的東東,那麼看了這一篇文章,你會對A*演算法從不知道變得了解,從瞭解變得理解。我不是一個純粹的遊戲開發者,我只是因為喜歡而研究,因為興趣而開發,從一些很小的遊戲開始,直到接觸到了

理解A*演算法過程

   這兩天研究了下 A* 尋路演算法, 主要學習了這篇文章, 但這篇翻譯得不是很好, 我花了很久才看明白文章中的各種指代. 特寫此篇部落格用來總結, 並寫了尋路演算法的程式碼, 覺得有用的同學可以看看. 另外因為圖片製作起來比較麻煩, 所以我用的是原文裡的圖片. &n

淺談遊戲中的A*演算法

本文為銳亞教育原創文章,轉載請註明轉載自銳亞教育 A*尋路 A*演算法基本原理 A*(唸作A星)演算法對初學者來說的確有些難度。本文並不試圖對這個話題作權威性的陳述,取而代之的是描述演算法的原理,使你可以在進一步的閱讀中理解其他相關的資

A*演算法補充知識

A*演算法 輔助知識 unity視覺化輔助工具Gizmos Gizmos.color =Color.red;//設定畫筆的顏色 Gizmos.DrawWireCube(位置,Vector3(長寬高));//畫出一個範圍框: Gizmos.DrawCube(位置,三維屬性長寬高); /

A*演算法之解決目標點不可達問題

在遊戲世界的尋路中,通常會有這樣一種情況:在小地圖上點選目標點時,點選到了障礙物或者建築上,然後遊戲會提示我們目標地點無法到達。玩家必須非常小心的在小地圖上點選目標區域的空白部分,才能移動到目標地點。那麼,有沒有辦法來改進一下這種不友好的體驗呢? 下面給出兩種方法: 最近

unity學習:演算法AStar演算法簡單AI(勢能場估價演算法

專案地址:https://github.com/kotomineshiki/AIFindPath 視訊地址:多重尋路 綜合尋路——包括攻擊考量的尋路演算法 GamePlay 這是一個《文明》+皇室戰爭的組合。 UI層使用狀態機來實現以下操作 1. 點選棋子再點選格子,