A*搜尋演算法,俗稱A星演算法。這是一種在圖形平面上,有多個節點的路徑,求出最低通過成本的演算法。常用於遊戲中的NPC(Non-Player-ControlledCharacter)的移動計算,或線上遊戲的BOT(ROBOT)的移動計算上。該演算法像Dijkstra演算法一樣,可以找到一條最短路徑;也像BFS一樣,進行啟發學習法的搜尋。
A*演算法是一種啟發學習法搜尋演算法,啟發學習法搜尋就是在狀態空間中的搜尋對每一個搜尋的位置進行評估,得到最好的位置,再從這個位置進行搜尋直到目標。這樣可以省略大量無謂的搜尋路徑,提高了效率。在啟發學習法搜尋中,對位置的估價是十分重要的。採用了不同的估價可以有不同的效果。
A*演算法的公式為:f(n)=g(n)+h(n),g(n)表示從起點到任意頂點n的實際距離,h(n)表示任意頂點n到目標頂點的估算距離。 這個公式遵循以下特性:
- 如果h(n)為0,只需求出g(n),即求出起點到任意頂點n的最短路徑,則轉化為單源最短路徑問題,即Dijkstra演算法
- 如果h(n)<=“n到目標的實際距離”,則一定可以求出最優解。而且h(n)越小,需要計算的節點越多,演算法效率越低。
對於函數h(n),估算距離常用的方法有:
- 曼哈頓距離:定義曼哈頓距離的正式意義為L1-距離或城市區塊距離,也就是在歐幾裡德空間的固定直角座標繫上兩點所形成的線段對軸產生的投影的距離總和。例如在平面上,座標(x1,y1)的點P1與座標(x2, y2)的點P2的曼哈頓距離為:|x1 - x2| + |y1 - y2|。
- 歐氏距離:是一個通常採用的距離定義,它是在m維空間中兩個點之間的真實距離。在二維和三維空間中的歐氏距離的就是兩點之間的距離。例如在平面上,座標(x1,y1)的點P1與座標(x2, y2)的點P2的歐氏距離為: sqrt((x1-x2)^2+(y1-y2)^2 )。
- 切比雪夫距離:是兩個向量之間各分量差值的最大值。例如在平面上,座標(x1, y1)的點P1與座標(x2, y2)的點P2的切比雪夫距離為:max(|x1 - x2| , |y1 - y2|)。
A*演算法實現虛擬碼:
function A*(start,goal) closedset := the empty set openset := {start} came_from := the empty map g_score[start] := 0 h_score[start] := heuristic_cost_estimate(start, goal) f_score[start] := g_score[start] + h_score[start] while openset is not empty x := the node in openset having the lowest f_score[] value if x = goal return reconstruct_path(came_from, came_from[goal]) remove x from openset add x to closedset foreach y in neighbor_nodes(x) if y in closedset continue tentative_g_score := g_score[x] + dist_between(x,y) if y not in openset add y to openset tentative_is_better := true else if tentative_g_score < g_score[y] tentative_is_better := true else tentative_is_better := false if tentative_is_better = true came_from[y] := x g_score[y] :=tentative_g_score h_score[y] :=heuristic_cost_estimate(y, goal) f_score[y] := g_score[y] +h_score[y] return failure function reconstruct_path(came_from,current_node) if came_from[current_node] is set p := reconstruct_path(came_from, came_from[current_node]) return (p + current_node) else return current_node
下面給出一個A*(曼哈頓距離)的例子:
■代表起點,■代表終點,■代表障礙,■代表屬於OPENSET,■代表屬於CLOSEDSET, ——
黃色線段代表最終得出的路徑。
方格內左上方代表f(n)即啟發函數值,左下角代表g(n),即起點到該點的距離,右下角代表h(n),即該點到終點距離的估值,使用曼哈頓距離,方格上下左右相鄰距離為10,對角線相鄰為14,曼哈頓距離以10為單位。
(gif動畫檔案)
A*與Dijkstra,DFS,BFS:
- A*演算法,每次從OPENSET中選擇 f(n) 最小的節點將其加入CLOESEDSET中,同時擴充相鄰節點,可把OPENSET看成一個優先隊列,key值為 f(n),優先順序最高的先出。
- Dijkstra演算法,每次從OPENSET中選擇 g(n) 最小的節點將其加入CLOSEDSET中,同時擴充相鄰節點,可把OPENSET看成一個優先隊列,key值為 g(n),優先順序最高的先出。
- DFS演算法,每次從OPENSET中選擇最晚被加入的節點將其加入CLOSEDSET中,同時擴充相鄰節點,可把OPENSET看成一個棧,後進先出。
- BFS演算法,每次從OPENGSET中選擇最早被加入的節點將其加入CLOSEDSET中,同時擴充相鄰節點,可把OPENSET看成一個隊列,先進先出。
下面通過幾個例子對比一下5種演算法,A*(曼哈頓距離),A*(歐氏距離),A*(切比雪夫距離),Dijkstra,Bi-Directional Breadth-First-Search ,以顯示A*演算法的優越性。
例一:
1.1 A*(曼哈頓距離)
1.2 A*(歐氏距離)
1.3 A*(切比雪夫距離)
1.4 Dijkstra
1.5 Bi-Directional Breadth-First-Search
例二:
2.1 A*(曼哈頓距離)
2.2 A*(歐氏距離)
2.3 A*(切比雪夫距離)
2.4 Dijkstra
2.5 Bi-Directional Breadth-First-Search
例三:
3.1 A*(曼哈頓距離)
3.2 A*(歐氏距離)
3.3 A*(切比雪夫距離)
3.4 Dijkstra
3.5 Bi-Directional Breadth-First-Search
例四:
4.1 A*(曼哈頓距離)
4.2 A*(歐氏距離)
4.3 A*(切比雪夫距離)
4.4 Dijkstra
4.5 Bi-Directional Breadth-First-Search
附:
我從網上找到的比較好的一個演算法示範程式,
http://download.csdn.net/detail/walkinginthewind/3822153