定向搜尋
在A*演算法的迴圈中,OPEN集合用來儲存所有用於尋找路徑的被搜尋節點。定向搜尋是在A*演算法基礎上,通過對OPEN集合大小設定約束條件而得到的變體演算法。當集合太大的時候,最不可能出現在最優路徑上的節點將會被剔除。這樣做會帶來一個缺點:由於必須得保持這樣的篩選,所以可選擇的資料結構型別會受到限制。
迭代深化(Iterative deepening)
迭代深化是一種很多AI演算法採用的方法,開始的時候給一個估計值,然後通過迭代使它越來越精確。這個名字來源於遊戲樹搜尋中對接下來幾次操作的提前預判(例如,在象棋遊戲中)。你可以通過向前預判更多的操作來深化遊戲樹。一旦當你的結果不發生變化或提高很多,就可以認為你已經得到了一個非常好的結果,即使讓它更精確,結果也不會再改善。在迭代深化A*(IDA*)演算法中,“深度”是 f 值當前的一個截斷值。當 f 值太大的時候,節點不會被考慮(也就是說,不會被加入到OPEN集中)。第一次迴圈時,只需要處理非常少的節點。隨後的每次迴圈,都會增加訪問的節點數。如果發現路徑得到優化,就繼續增加當前的截斷值,否則結束。更多細節,參見連結。
我個人並不看好IDA*演算法在遊戲地圖尋路中的應用。迭代深化的演算法往往增加了計算時間,同時降低了記憶體需求。然而,在地圖尋路的場景中,節點僅僅包含座標資訊,所需要的記憶體非常小。所以減少這部分記憶體開銷並不會帶來什麼優勢。
動態加權
在動態加權演算法中,你假定在搜尋開始時快速達到(任意)一個位置更為重要,在搜尋結束時到達目標位置更為重要。
1 |
f(p) = g(p) + w(p) * h(p) |
有一個權值(w >= 1 )和該啟發式關聯。當不斷接近目標位置的時候,權重值也不斷降低。這樣降低了啟發式函式的重要性,並增加了路徑實際代價的相對重要性。
頻寬搜尋
頻寬搜尋有兩個被認為非常有用的特性。這個演算法變體假設 h 是一個估計過高的值,但它的估計誤差不會超過 e。那麼在這樣的條件下,搜尋到的路徑代價與最優路徑代價的誤差不會超過 e。這裡需要再一次強調,啟發值設定得越好,那麼得到的結果也將越好。
另外一個特性是用來判斷你是否可以刪掉OPEN集合中的某些節點。只要 h+d 大於路徑真實代價(對於一些 d),那麼你可以丟掉任意滿足其 f 值比OPEN集合中最優節點 f 值至少大 e+d 的節點。這是一個很奇異的特性。你相當於得到了一個 f 值的頻寬;所有在這個頻寬意外的節點都可以被丟棄掉,因為他們被保證一定不會出現在最優路徑中。
有意思地是,對於這兩種特性分別使用不同的啟發值,仍然可以計算得到結果。你可以使用一個啟發值來保證路徑代價不會太大,另外一個啟發值來決定丟棄掉OPEN集中的哪些節點。
雙向搜尋
與從頭到尾的搜尋不同,你也可以並行地同時進行兩個搜尋,一個從開始到結束,一個從結束到開始。當它們相遇的時候,你就會得到一個最優路徑。
這個想法在一些情況下非常有用。雙向搜尋的主要思想是:搜尋結果會形成一個在地圖上呈扇形展開的樹。而一個大的樹遠不如兩個小的樹,所以使用兩個小的搜尋樹更好。
面對面的變體將兩個搜尋結果連結到一起。該演算法選擇滿足最佳 g(start,x) + h(x,y) + g(y,goal) 的一對節點,而不是選擇最佳前向搜尋節點 g(start,x) + h(x,goal) 或者最佳後向搜尋節點 g(y,goal) + h(start,y)。
重定向演算法放棄同時前向和後向的搜尋方法。該演算法首先進行一個短暫的前向搜尋,並選出一個最佳的前向候選節點。接著進行後向搜尋。此時,後向搜尋不是朝向開始節點,而是朝向剛剛得到的前向候選節點。後向搜尋也會選出一個最佳後向搜尋節點。然後下一步,再執行前向搜尋,從當前的前向候選節點到後向候選節點。這個過程將會不斷重複,直到兩個後選節點重合。
動態A*與終身規劃A*
有一些A*的變體演算法允許初始路徑計算之後地圖發生改變。動態A*可以用於在不知道全部地圖資訊的情況進行尋路。如果沒有全部資訊,那麼A*演算法的計算可能會出現錯誤,動態A*的優勢在於可以快速改正那些錯誤而不會花費很多時間。終身規劃A*演算法可以用於代價發生改變的情況。當地圖發生改變的時候,A*計算得到路徑可能會失效;終身規劃A*可以重複利用以前的A*計算來產生新的路徑。
然而,動態A*與終身規劃A*都要求大量的空間——執行A*演算法時需要保持它的內部資訊(OPEN/CLOSED集合,路徑樹,g值)。當路徑發生改變的時候,動態A*或終身規劃A*演算法會告訴你是否需要根據地圖的變化調整你的路徑。
對於一個有大量運動單元的遊戲,通常不會想要儲存所有的資訊,所以動態D*和終身規劃A*可能不適用。這兩種演算法主要為機器人而設計。當只有一個機器人的時候,你不需要為了其他機器人的路徑來重複使用記憶體。如果你的遊戲只有一個或比較少的單元,你能會想要研究一下動態A*或者終身規劃A*演算法。
跳躍點搜尋
提高A*演算法計算速度的大多數技術都是採取減少節點數量的策略。在統一代價的方格網路中,每次單獨搜尋一個獨立格空間是非常浪費的。一個解決辦法是對其中關鍵節點(例如拐角)建立一個用來進行尋路的圖。但是,沒有人願意預先計算出一個路標圖,那就來看看可以在網格圖上向前跳躍的A*變體演算法,跳躍點搜尋。 考慮到當前節點的孩子節點有可能會出現在OPEN集合中,跳躍點搜尋直接跳躍到從當前點可看到的遙遠的節點。隨著OPEN集合中節點的不斷減少,每一步的代價都會越來越高雖然都很高,但是步數也會越來越少。相關細節,可以參考連結;這篇部落格中有很好的視覺化解釋;還有,reddit上對優缺點的討論可點選這個連結。
此外,在矩形對稱消減中,有對地圖進行分析和圖中嵌入跳躍。這兩種技術都是應用於方格網路圖中的。
Theta*
有時網格會用來尋路是因為地圖是用網格來生成,而不是因為真的要在網格上移動。如果給定一個關鍵點的圖(例如拐角)而不是網格的話,A*演算法可以執行得更快並得到更優的路徑。但是,如果你不想預先計算那些圖的拐角,你可以通過A*演算法的變體Theta*在方格網路上進行尋路而不必嚴格遵循那些方格。當構建父親指標的時候,如果有一個祖先與該節點間存在邊,那麼Theta*演算法會直接將該指標指向該祖先而忽略所有的中間節點。不像路徑光滑那樣將A*找到的路徑變為直線,Theta*可以把那些路徑的分析作為A*演算法過程的一部分。這樣的做法可以比後處理方格路徑使之成為任意傾角的路徑的方式,可以得到更短的路徑。這篇文章的是對演算法的一個比較合理的介紹,另外可參考懶惰Theta*。
Theta*的思路也可能被應用於導航網格。