啟發式搜索技術A*


開篇

這篇文章介紹找最短路徑的一種算法,它的字我比較喜歡:啟發式搜索。

對於入門的好文章不多,而這篇文章就是為初學者而寫的,很適合入門的一篇。文章定位:非專業性A*文章,很適合入門。

有圖有真相,先給大家看個效果圖吧:從圖的左下角到右上角尋找最短路徑,灰色部分是障礙物。

這是用一般的搜素方法,類似窮舉的效果

下面的圖是用A*搜素的效果,也就是本文要介紹的算法。

可以看出,用A*算法減少了許多計算量,它的效率有了顯著的提高。

下面將為你解答上圖中的算法是如何實現的。

圖片來源:http://en.wikipedia.org/wiki/A*_search_algorithm

正文

搜索區域介紹

下圖是這篇文章討論的中心:

圖中左邊的綠色點是搜索的起點A,目標點是右邊的紅色點B,中間被障礙物擋住(藍色部分)。

我們的目的是從起點出發,找到一條到達目標點的最短路徑。

把整個圖都分為一個個小方塊只是為了這樣方便討論,更多的應用中,也可以把圖分為其它方塊的組合。

開始搜索

目標是找出從A點出發到B的最短路徑,所以我們從A點開始搜索,直到找到目標B。

搜索的步驟是這樣的:

1、從起點A開始把A加入到openlist中。openlist解釋:它是一個隊列,里面元素是一些方塊,它們有可能構成最短路徑。現在隊列中只有元 素A,以后會加入更多的元素。以后會對里的元素進行檢查,從里面來找到構成最短路徑的元素。

2、看起點A周圍的元素是否可達(是否能從A到達它們)把從A可到達的元素加入到openlist中,並且加入到openlist中的節點維護一個指指針,指向他的父親,也即A點。如果A周圍有障礙物就忽略它。從這個圖看, A周圍把個元素都可達,所以把它們都加到openlist中。

3、把起點A放入closelist中,在closelist中的點意味着以后不需要再去考慮它了。對於A節點,A可達的點都加入到了openlist中,以后也就不用考慮A的情況了。

經過以上三步操作后的效果圖如下所示

圖中被暗綠色包圍的就是openlist中的點,一共八個,都是從起點A可達的點,並且他們中的每個都有一個指向他們父節點的指針(圖中的小針方向)被高亮綠色包圍的表示closelist中的點,可以看出起點A已經在closelist中。

路徑選擇

從起點出發 ,下一步可以走的點現在有八個,選取哪一個作為下一步的點呢?正常的思維是選取一個離目標值最進,且在這些點中離遠點最近的點。

本文的思路也是這樣的,文中用

F = G + H

表示,其中:

對於每個點,都有自己的G、H、F。

其中G表示從特定的點到起點的距離,H表示從該點到目標的估值,那么F就是經過該點路徑的估值。

下面詳細介紹

G:從起點到特定節點的距離,也就是G的父節點加上從G的父節點到起點A的距離g。圖中是邊長為10的正方形塊,所以就是G的父節點的值g

加上10(上下左右相鄰)或者加上14(斜塊相鄰、也就是對角線的長度,本來是14.14、、為了方便計算這里取近似值)

H:H能用很多方法得到估計值.這里用到的方法稱為Manhattan method,H的值就是從考慮的點通過水平和垂直移動達到目標點的移動步數乘10(正方形塊的邊長為10).注意只是水平和垂直移動,不走斜線。並且忽略圖中的障礙物。

插一句:

看了對H的描述,你可能會懷疑這種估計的精確性,有一點是可以肯定的:估計值越接近真實值,算法就能更塊的找出最短路徑。我們用的這種方法確實是做了估計,只是這種估計准確性不高,就是說只是粗略的估計,因為這種方法容易理解,所以才采用這種方法。可以想到,太過接近的估值最后不一定能得到想要的結果。關於估值函數想了解更多請參見:http://www.policyalmanac.org/games/heuristics.htm

為了從openlist中選取一個點繼續搜索,就要計算出openlist中的每個點的F、H、G的值然后選取F小的一個點,進行下一步的探索。

對於上圖中的點,他們的F、G、H的值在圖中都有標明。

F、H、G的位置在起點右邊的點中已經有標注,其他點的位置同理。

現在看起點右邊的點(也就是標有字母的點)G=10,因為在起點正左邊。H=30,水平移動三個格子可以到目標點B。F=G+H=40

繼續搜索

由於我們的目的是找最短路徑 ,下一步就從openlist中選取F最小的點做進一步的搜索,按如下步驟進行:

(為了方便描述,把選取的點成為點M)

1、檢查M周圍的點,在closelist中則忽略它,如果可達且不在openlist中,則加入openlist中,同理的維護一個指向父節點的指正,同時計算加入點的F H G 值。

2、如果M周圍的點在openlist中,則看從起點A通過M到這類點的路徑是不是小於他們的G值,如果是則更新他們的G、F值(更新為小的)。如果不是則不做任何操作。

3、把M從openlist中移除,加入closelist中。

對openlist中F最小的點(也就是起點左邊的點)的處理效果如下圖所示:

M的右邊、右上、右下是障礙物,所以忽略他們。M的左邊點在closelist中,也不去管他,剩下的是M的上、下、左上、左下的點。他們已經在openlist中,所以看從起點通過M到他們的距離是不是小於他們的G值。通過判斷,都比他們的G值大,所以做任何操作。

可以看出,現在的closelist已有兩個元素了(高亮綠色包圍的塊)

下一步的操作和上面敘述的一樣,從openlist中找出F最小的,重復上的操作。從圖中可以看出,現在的openlist中F最小的有兩個,就是剛剛考慮的點的正上方和正下方,其實這里選哪個都無所謂,只是人們習慣於選擇較晚加入到openlist中的元素,這里選擇下方的點。

同理,處理效果如下圖所示:

下面簡單的說下處理過程:

暫且稱現在處理的點為N吧。

N上方  在closelist中,不考慮。

N左方 在openlist中,看從原點通過N到它的距離為14+10大於10,不做操作,跳到下一步

N的左下方,下方 加入openlist中,同時記錄F、G 、H的值還有指向父節點的指針。

N的右下方這里看做“不可達的點”原因是這兩個點都處於障礙物的對角上,當然這只是一種人為的規定。也可以取消這條規定就把它加入到openlist中。這只是一種規定,不必深究。

處理的結果是closelist中現在有三個元素,用高亮的藍色標記,同樣的,openlist中的元素用暗綠色標記出。

 

重復上的步驟,每次從openlist中選取F最小的點加入closelist中,同時處理這個點周圍的元素。。

直到目標節點也被加入到closelist中停止。

處理的效果如下圖所示:

如果用心看、你也許已經發現了,在起點正下方兩個點的G值,沒錯,就是圖中用橢圓圈起來的點,之前的G=28,現在是20。這是在算法進行的時候更新的,可能 是這其中的某一步,處理這個點的時候,發現了一條更短的路徑20,替換了原來的28。

到這里,問題已經基本解決了,最后的任務就是得到這條路徑。

只要從目標點出發,沿着他們的父節點遍歷,直到起點。就得到了一條最短路徑。

如下圖所示

總結

 現在你應該對A*算法有一個初步的認識了吧,總結下算法的實現過程:

1、把起點加入到openlist中

2、重復以下步驟

  a、從openlist中找出F最小的節點,並把它當做當前的操作節點

  b、檢查當前點周圍的點,如果已經在openlist中看是否能通過當前點得到更小的G,如果能就更新那個點的G,F的值,如果在closelist中或者是障礙物(不可達)則忽略他們

  c、把當前點從openlist中移除 ,加入closelist中

  d、當目標點加入closelist中時停止

3、保存路徑,從目標點出發,按照父節點指針遍歷,直到找到起點。

后記

 其實啟發式搜索就是對窮舉的一種優化,讓每次搜索都更接近目標。這就要通過估值函數實現,對於這類問題,找到一個估值函數是關鍵。

估值函數:從當前點出發到目標點的花費。其實從這個理念上說,好像和分支界限法有些類似,都是在窮舉的基礎上對搜素優化。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM