1. 程式人生 > >【綜合演算法】A*演算法

【綜合演算法】A*演算法

A*演算法

A*演算法;A*(A-Star)演算法是一種靜態路網中求解最短路徑最有效的直接搜尋方法,也是許多其他問題的常用啟發式演算法。注意是最有效的直接搜尋演算法。之後湧現了很多預處理演算法(ALT,CH,HL等等),線上查詢效率是A*演算法的數千甚至上萬倍。

  在遊戲、優化領域,A*演算法是很重要的一個演算法。例如RTS遊戲中控制移動單位到另外一個地點,玩家只需要在指定地點下達指令,移動單位可以自動搜尋最好的路徑抵達目的地。
  在路徑搜尋方面,A*演算法的目標是找到當前已知約束條件下的最優路徑。由於A*演算法是直接搜尋方法,沒有全域性優化,並且我們並不知道實際情況有多複雜,所以A*演算法最後不一定能得出全域性最短路徑,而是得到當前已知約束條件下的最優路徑,甚至可以根據實際情況,在路徑搜尋速度和路徑搜尋質量上取得平衡。
  A*演算法可以看做迪傑斯特拉最短路徑演算法和最優貪心演算法的綜合。相比傳統的迪傑斯特拉演算法,A*演算法在每個路徑節點的權值計算有所不同。A*演算法的權值計算表示為:f

(n)=g(n)+h(n),其中f(n)是最終的權值,g(n)是初始點到當前點的代價,類比於迪傑斯特拉演算法的節點權值,在遊戲中山地區域的權值就比較大,平原區域權值比較小,那麼移動單位會傾向於走平原地區;h(n)則是當前節點到目標節點的估計距離。路徑搜尋速度和路徑搜尋質量主要是通過h(n)來控制。如果h(n)能非常好的反映當前節點到目標節點的距離度量,那麼A*演算法得到的搜尋路徑就等於或逼近於全域性最短路徑;如果h(n)精準地反映當前節點到目標節點的距離度量,那麼實際上我們已經知道當前節點到目標節點的最短路徑,也就沒A*演算法什麼事了;如果h(n)接近或者等於0,那麼A*演算法退化為普通的迪傑斯特拉演算法;如果h
(n)
權重遠比h(n)大,那麼A*演算法退化為普通的路徑搜尋演算法。
  h(n)的計算方法有很多種。設當前點為(in,jn),目標點為(id,jd)。比較簡單的距離度量有曼哈頓距離,即h(n)=α[abs(inid)+abs(jnjd)],其中α控制h(n)的作用權重;計算量稍大的有歐式距離,即h(n)=α(inid)2+(jnjd)2;也可以根據實際情況考量,設定自定義的距離度量。
  一般情況下,設上一級搜尋的節點為n,其權值為f(n)=g(n)+h(n),下一級搜尋到的節點為n+1,則權值為f(n+1)=g(n)+Δg(n)+h(n+
1)
。這裡Δg(n)指代在迪傑斯特拉演算法情況下權值的增量,這說明搜尋過程中g(n)是累加的,具有記憶效應;而h(n)則需要隨時更新,是瞬時的。
  另外,格子的走法也需要設定。普通的方格路徑,我們需要考量是否可以斜著行進,既可以設定當前點的斜向鄰點是否可以移動,也可以只是設定斜向鄰點具有稍微大點的權值;在《文明》系列遊戲中,單位方格則是六邊形方格,角色可以選擇移動到周圍六個方格。
  A*演算法的虛擬碼非常簡單,百度百科摘錄如下:

建立兩個表,OPEN表儲存所有已生成而未考察的節點,CLOSED表中記錄已訪問過的節點。計算算起點的h(s);將起點放入OPEN表;
while(OPEN!=NULL)
{
 從OPEN表中取f(n)最小的節點n;
  if(n節點==目標節點)
   break;
{
  計算f(X);
   if(X in OPEN)
{
   if(新的f(X)小於OPEN中的f(X)){
   把n設定為X的父親;
  更新OPEN表中的f(n);
}
if(X in CLOSE)
continue;
if(X為全新節點)
{
把n設定為X的父親;
求f(X);
並將X插入OPEN表中;//還沒有排序
}
}//endfor
將n節點插入CLOSE表中;
按照f(n)將OPEN表中的節點排序;//實際上是比較OPEN表內節點f的大小,從最小路徑的節點向下進行。
}//endwhile(OPEN!=NULL)

  做完計算之後,如果遇到目標點,那麼從目標點開始沿著父節點向上回溯到起始節點,然後對搜尋路徑執行反向操作,就得到了起始點到目標點的路徑。
  讀懂上述程式碼就知道A*演算法的實現方法,可以說邏輯上比較簡單。存在的問題主要在如何給出h(n),如何用資料結構表示,如何同時提升搜尋質量和搜尋速度。這些就靠程式設計功力了。
  下面給出一部分使用曼哈頓度量計算的結果圖和說明,圖中包含一個白色C型障礙物,左邊的小白點是起始點,右邊的小白點是目標點,灰色區域表示搜尋範圍:
  0.0wet
  曼哈頓距離權值α=0,演算法退化為迪傑斯特拉演算法,搜尋範圍是以起始點為中心的方框。該搜尋能獲取全域性最短路徑,但是搜尋速度非常慢,因此我終止了搜尋。
  0.8wet
  曼哈頓距離權值α=0.8演算法搜尋範圍極大的縮小了。
  1wet
  曼哈頓距離權值α=1.0搜尋範圍變大,但是穿過障礙物之後行走一條最短路徑。
  1.5wet
  曼哈頓距離權值α=1.5演算法搜尋範圍更大。路徑有些斜扭,但仍然是當前最優路徑。