日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

A*,那个传说中的算法

發(fā)布時間:2023/12/20 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 A*,那个传说中的算法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

周日的下午微信simplemain,老王又來找大伙兒聊技術(shù)了~~

?

今天想跟大家聊的,是我們經(jīng)常用到,但是卻讓大家覺得十分神秘的那個算法:A* 。

?


想必大家都玩兒過對戰(zhàn)類的游戲,老王讀書那會兒,中午吃完飯就會跟幾個好哥們兒一起來兩局紅警。后來升級了,玩兒星際(是不是暴露年齡了,哈哈~~)。

?

玩兒的時候,就會發(fā)現(xiàn)這里面的兵(為了方便描述,把坦克、飛艇、礦車、龍騎等統(tǒng)稱為兵),你只要指定好地點(diǎn),他們就會自己朝目的地進(jìn)發(fā),最終去向你指定的地點(diǎn)。不過紅警的實現(xiàn)似乎要差一點(diǎn),經(jīng)常走繞路,然后在路上就莫名其妙被人干了……

?

于是,老王就對這個找路算法做了些研究,去查了查資料。所有的資料都一致顯示,這些尋路算法,基本上使用的都是一個叫做A*的算法。不過當(dāng)時看了算法,沒有去實踐,所以也沒有太深入的思考,只是知道他是一種啟發(fā)式的搜索算法,能夠比較快的找到相對優(yōu)的路徑。說來也巧,后來因為百度的A-Star算法比賽進(jìn)入百度實習(xí),才了解了很多互聯(lián)網(wǎng)相關(guān)的技術(shù)。

?

說在前面的話:因為老王不是做游戲的,游戲的尋路算法肯定有做各種優(yōu)化,老王只是聊聊自己理解的A*算法,所以講的不對的地方請專家們指正,專家們切勿生氣^_^

?

好了,背景說完了,我們開始吧~

?

廣度優(yōu)先(BFS)和深度優(yōu)先(DFS)搜索

在談A*之前,還是要先聊聊搜索算法中的老祖宗,深度和廣度優(yōu)先搜索算法。這兩個算法,基本上各教科書都會有講解,各種面試基本上也都會面到。不過為了講清楚A*,我們還是先一起來看看他們吧。

?

深度優(yōu)先搜索,用俗話說就是不見棺材不回頭。算法會朝一個方向進(jìn)發(fā),直到遇到邊界或者障礙物,才回溯。一般在實現(xiàn)的時候,我們采用遞歸的方式來進(jìn)行,也可以采用模擬壓棧的方式來實現(xiàn)。

?

如下圖,S代表起點(diǎn),E代表終點(diǎn)。我們?nèi)绻凑沼摇⑾隆⒆蟆⑸线@樣的擴(kuò)展順序的話,算法就會一直往右擴(kuò)張,直到走到地圖的右邊界,發(fā)現(xiàn)沒找到目標(biāo)點(diǎn),然后再回溯。

?


這個算法的好處就是實現(xiàn)簡單,可能就十幾行代碼。不過問題也很明顯,就是:

1、路徑可能不是最優(yōu)解;

2、尋路時間比較長。

?

廣度優(yōu)先搜索,這個用形象的比喻,就像是地震波,從起點(diǎn)向外輻射,直到找到目標(biāo)點(diǎn)。我們在實現(xiàn)的時候,一般采用隊列來實現(xiàn)。

?


這個算法的優(yōu)點(diǎn):

1、簡單。代碼也就幾十行;

2、路徑能找到最優(yōu)解;

?

不足:

1、算法消耗的時間比較大,遍歷的點(diǎn)會很多。

?

這里就引出一個問題:為什么廣度優(yōu)先算法能找到最優(yōu)路徑,但是卻很耗時呢?

?

A*算法

廣度優(yōu)先搜索之所以能找到最優(yōu)的路徑,原因就是每一次擴(kuò)展的點(diǎn),都是距離出發(fā)點(diǎn)最近、步驟最少的。如此這樣遞推,當(dāng)擴(kuò)展到目標(biāo)點(diǎn)的時候,也是距離出發(fā)點(diǎn)最近的。這樣的路徑自然形成了最短的路線。

?

任何事情都有正反兩面。正是由于廣度優(yōu)先搜索一層層的擴(kuò)展,雖然讓他找到了最優(yōu)的路線,但是,他卻很傻的走完了絕大多數(shù)格子,才找到我們的目標(biāo)點(diǎn)。也就是,他只關(guān)注了當(dāng)前擴(kuò)展點(diǎn)和出發(fā)點(diǎn)的關(guān)系,而忽略了當(dāng)前點(diǎn)和目標(biāo)點(diǎn)的距離。如果,如果,如果……我們每擴(kuò)展一個點(diǎn),就踮起腳尖,看看詩和遠(yuǎn)方,找找我們要尋找的那個目標(biāo),是不是就有可能指引我們快速的去往正確的方向,而不用傻乎乎的一層層的發(fā)展了呢?

?

我們來看看下圖:

?


同樣是從出發(fā)點(diǎn)S走了兩步以后到達(dá)的M1和M2兩個點(diǎn),如果讓你來選擇,你會選擇他們中的誰來做擴(kuò)展點(diǎn)呢?很明顯,只要是眼力不差的人,都會選擇M1。為什么呢?因為M2需要再走9步,才能到達(dá)終點(diǎn)E;而M1只需要7步!!!

?

注意了!我們的判斷依據(jù),除了考慮了中間這個點(diǎn)同出發(fā)點(diǎn)的距離以外,還考慮了這個點(diǎn)同目標(biāo)點(diǎn)的距離,對吧~

?

如果你想到了這一點(diǎn),恭喜你,你已經(jīng)掌握了A*算法的秘訣了:A*算法相對廣度優(yōu)先搜索算法,除了考慮中間某個點(diǎn)同出發(fā)點(diǎn)的距離以外,還考慮了這個點(diǎn)同目標(biāo)點(diǎn)的距離。這就是A*算法比廣度優(yōu)先算法智能的地方。也就是所謂的啟發(fā)式搜索。

?

我們簡單的抽象一下,如果用f(M)表示:從起點(diǎn)S到終點(diǎn)E(經(jīng)過M點(diǎn))的距離,那他就可以表示成為兩段距離之和,即:S→M的距離 + M→E的距離。如果我們用符號表示的話,就可以寫成:f(M) = g(M) + h(M)。

?


怎么樣,看起來這個公式是否是很簡單呢?

?

我們擴(kuò)展到M點(diǎn)的時候,S→M的距離就已經(jīng)知道,所以g(M)是已知的。但是M到E的距離我們還不知道。如果我們能用某種公式,能大概預(yù)測一下這個距離,而這個預(yù)測的值又比較精確,我們是不是就能很精確的知道每一個即將擴(kuò)展的點(diǎn)是否是最優(yōu)的解路徑上的點(diǎn)呢?這樣找起路來,是不是就很快呢?

?

所以,接下來最關(guān)鍵的問題,就是怎么計算這個h(M)的值!

?

可能大家都會問一個問題:從M→E的距離不是很好計算嘛?用橫向的距離+縱向的距離就完了!

?

這個問題問的很好,但是結(jié)論是:既對,又不對。如果按照我們之前的圖來看,這個結(jié)論是正確的。但是,如果是下面這張圖呢?

?


在M和E之間,有一堵藍(lán)色的墻,這個時候,M→E的距離,還是橫向的直線距離 + 縱向的直線距離嘛?明顯不是了,他需要繞道!

?

這個時候,似乎希望破滅了……

?

前兩天有個朋友給我說,兩口子的相處之道,就是相互包容,不要太較真兒。如果我們將這個思想用到這里,把h(M)看做一個估計的值,而不是精確值,那問題是不是就解決了呢?

?

也就是說,我們盡可能找那些f(M)=g(M)+h(M)小的點(diǎn)(其中h(M)是個估算值),當(dāng)做我們的路徑經(jīng)過點(diǎn),即使實際的h'(M)值可能和h(M)值不等也沒關(guān)系,我們就當(dāng)做一個參考(總比廣度優(yōu)先搜索好吧~)。如果通過這個估算,能干掉很多明顯很差的點(diǎn),我們也就節(jié)省了很多不必要的花銷,也算賺到了,對吧~

?


比如,上圖中, M點(diǎn)即使是繞路,也比M'點(diǎn)要強(qiáng),對吧。在估算的時候,我們就可以將S左邊的點(diǎn)基本上都拋棄掉,從而減少我們擴(kuò)展的點(diǎn)數(shù),節(jié)約計算的時間。

?

說完上面的東東,我們大面兒上的東西就說的差不多了,接下來就省兩個問題要去解決了:

1、這個估算的函數(shù)h(M)怎么樣去計算?

2、對于不同的估算函數(shù)h(M)來講,對于我們的搜索結(jié)果會有什么樣的影響?

?

那我么一個個的來回答吧。

?

估算函數(shù)h(M)如何計算?

常見的距離計算公式有這么幾種:

?

1、曼哈頓距離:這個名字聽起來好高端,說白了,就是上面我們講的橫向格子數(shù)+縱向格子數(shù);

2、歐式距離:這個名字聽起來也很高端,說白了,就是兩點(diǎn)間的直線距離sqrt((x1-x2)2 + (y1-y2)2)

?

除了上述的距離計算公式以外,還有一些變種的距離計算公式,如:對角線距離等等。這個就在具體的問題中做具體的優(yōu)化了。

?

不同估算函數(shù)對于結(jié)果的影響

那距離公式選擇不同,對我們的尋路結(jié)果有哪些影響呢?

?

1、當(dāng)估算的距離h完全等于實際距離h'時,也就是每次擴(kuò)展的那個點(diǎn)我們都準(zhǔn)確的知道,如果選他以后,我們的路徑距離是多少,這樣我們就不用亂選了,每次都選最小的那個,一路下去,肯定就是最優(yōu)的解,而且基本不用擴(kuò)展其他的點(diǎn)。如下圖:

?


2、如果估算距離h小于實際距離h'時,我們到最后一定能找到一條最短路徑(如果存在另外一條更短的評估路徑,就會選擇更小的那個),但是有可能會經(jīng)過很多無效的點(diǎn)。極端情況,當(dāng)h==0的時候,最終的距離函數(shù)就變成:

?

f(M)=g(M)+h(M)

=> f(M)=g(M)+0

=> f(M)=g(M)

?

這不就是我們的廣度優(yōu)先搜索算法嘛?! 他只考慮和起始點(diǎn)的距離關(guān)系,毫無啟發(fā)而言。

?


3、如果估算距離h大于實際距離h'時,有可能就很快找到一條通往目的地的路徑,但是卻不一定是最優(yōu)的解。

?

因此,A*算法最后留給我們的,就是在時間和距離上需要考慮的一個平衡。如果要求最短距離,則一定選擇h小于等于實際距離;如果不一定求解最優(yōu)解,而是要速度快,則可以選擇h大于等于實際距離。

?

好了,口水話講了這么多,來看代碼吧。老王粘貼了最核心的那段代碼,如下:

?


完整的代碼請參見老王的github:

https://github.com/simplemain/astar

?

老王定義了一張地圖:

?


當(dāng)用以下距離公式計算h值的時候,效果如圖:

1、曼哈頓距離:

?


很明顯,大部分的空白點(diǎn)都沒有去遍歷,而且最終找到了最優(yōu)的路徑。

?

2、歐式距離:

?


同曼哈頓距離一樣,效果差不多,不過多擴(kuò)展了幾個點(diǎn)。

?

3、歐式距離的平方

?


這種情況就是h值大于等于實際距離的,明顯他擴(kuò)展的點(diǎn)很少,不過找到的路徑卻不是最短路徑。

?

4、BFS的情況(h值恒為0)

?


這種算法基本等同于BFS,所有點(diǎn)基本都被擴(kuò)展了,但是還是找到了最優(yōu)的那個路徑。

?

好了,以上就是今天的內(nèi)容,你看懂了嘛?如果覺得老王講的還有點(diǎn)意思,就請繼續(xù)關(guān)注老王的微信吧,每周固定時間,不見不散哦~



總結(jié)

以上是生活随笔為你收集整理的A*,那个传说中的算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。