我們平常所見的深度優先和廣度優先搜尋演算法都是直接搜尋演算法,這種是盲目式的搜尋,直到搜尋時遇到終點,或者搜尋整個地圖結束。而a*演算法則是啟發式搜尋,這種搜尋就是在狀態空間中的搜尋對每乙個搜尋的位置進行評估,得到最好的位置,再從這個位置進行搜尋直到目標,它是通過啟發函式引導演算法的搜尋方向。
a*演算法路徑代價值計算:f=g+h; (啟發函式)
f:從起點經過當前點到到終點的代價值;
g:從起點到當前點的實際代價;
h:從當前點到終點的估計代價;兩種方法計算: 歐幾裡(兩點間的直線距離)
曼哈頓(x軸的距離 + y軸的距離);
在下面的例子中,為方便計算,橫向和縱向的移動代價為 10 ,對角線的移動代價為 14 。
開啟列表:存放待處理節點,
關閉列表:存放不需要再次檢查的節點
(1)把起始點的格仔位置加入到開啟列表,然後開始迴圈從開啟列表中每次找到f值最小的格仔(第一次就是起始點),此時將格仔從開啟列表取出,放到關閉列表,代表此格仔已經被訪問。因為在本次迴圈中被取出,我們稱它為當前格。
(2)然後我們遍歷當前格的周圍8個格仔,如果不在開啟列表,就新增到開啟列表,並計算每乙個格仔的f,g,h的值,同時把當前格設定為它的父節點(即用來記錄這個格仔的前乙個格仔)。
(3)如果當前格的周圍8個格仔中,某些點已經在開啟列表中,需要重新檢查當前的路勁是否比原來計算的好,則重新計算g值:新g值為 = 當前點的g值 + 當前格到這個格的代價值(10或14)。如果新g值比原來的小,則把當前格設為這個格仔的父節點。
(4)最後我們在開啟列表中查詢,如果終點已在當前開啟列表中,說明找到,結束迴圈,如果開啟列表為空了,還沒找到終點
說明終點不可達。
偽**流程分析:
例子:
步驟:(1)第一次將起點43新增到開啟列表。
(2)開始迴圈,從當前開啟列表中找到f最小的點(這裡只有起始點,當然是起始點),新增到關閉列表。
(3)找43周圍的8個點,因為都還不在開啟列表,而且都可達,所以都新增到開啟列表,計算每個點f,g,h的值,同時把43設定為它們的父節點。
(4)此時檢查終點是否在開啟列表,不在,進行下一輪迴圈。
(5)從開啟列表中取出f值最小的點,這裡是34。
(6)找34周圍的8個點,找到23,24還不在開啟列表,而且都可達,所以新增到開啟列表,計算他們的f,g,h的值,同時把34設定為它們的父節點。至於34其他周圍的點,如果已經在開啟列表了,那麼重新計算一下g值,判斷34到這個點這條路徑的g值是否小於原來的g值,如果小於則更新父節點為34,並重新賦值f,g,h的值。
(7)同理,每次迴圈檢查終點是否在開啟列表,若不在,繼續進行下一輪迴圈,直到終點在開啟列表或開啟列表為空。
主要**:
point* astar::findpath(point &startpoint, point &endpoint, bool isignorecorner)
//對某乙個格仔,它在開啟列表中,計算g值, 如果比原來的大, 就什麼都不做,否則設定它的父節點為當前點,並更新g和f
else
}//查詢結束點是否已經在開啟列表中,如果在,這時候路徑被找到。
point *respoint = isinlist(openlist, &endpoint);
//如果返回不為空,表示找到終點,則通過終點的parent一直反推得出路徑
if (respoint)
return respoint;
}}while (!openlist.empty());//當開啟列表為空時,跳出迴圈
return null;
}
一些輔助函式:
int astar::calcg(point *temp_start, point *point)
int astar::calch(point *point, point *end)
int astar::calcf(point *point)
point* astar::getleastfpoint()
return null;
}
總結:
a*演算法
開啟列表:存放待處理節點,
關閉列表:存放不需要再次檢查的節點
f = g + h,選取f值最低的那個方格
f:每個可能試探點的估值
g:表示從起始搜尋點到當前點的代價
h:它表示啟發式搜尋中最為重要的一部分,即當前結點到目標結點的估值。
h(n)的一般計算方法:假設當前節點(x1,y1),目標節點的位置是(x2,y2),則可以用兩種方法計算h,歐幾里得距離h(n) = sqrt((x2-x1) *(x2-x1) + (y2-y1) *(y2-y1)),曼哈頓距離h(n) = abs(x2-x1) + abs(y2-y1)。
a*演算法的改進
第一次訪問到該節點時,可能並不是最短路徑,但在之前的做法中,已經將該節點放入closed list中,此後不在考慮。更好的做法是及時動態更新節點資訊。也就是說,對closed list中的節點也考慮新的估值,若小與原估值,則放入open list中重新處理。
對open list,演算法中需要經常訪問,查詢最小f值節點,而open list比較大,因此應該考慮效率問題。可以使用效率高的排序、查詢方法,例如二叉堆,這裡我們使用小根堆。
《演算法筆記》Dijkstra演算法筆記
今日在華農終於接近完成閱讀演算法筆記,有點點成就感,做下dijkstra跟dfs演算法結合的筆記 簡單狀態 純dijkstra include include include define inf 1000000000 using namespace std const int maxn 1010 ...
回溯 皇后 演算法筆記 演算法筆記
分治演算法 線性時間選擇 o n 33 隨機線性選擇 偽 o n int partition type a,int p,int r return table n 1 w 1 main function else else lowcost i 0 for int i 1 i n i int temp ...
回溯 皇后 演算法筆記 演算法筆記
遞迴演算法 能夠用遞迴解決的問題需要滿足三個條件 原問題可以轉換為乙個或多個子問題來求解,而這些子問題的求解方法和原問題完全相同,只是規模不同 遞迴呼叫次數必須是有限的 必須有結束遞迴的條件 遞迴出口 來終止遞迴。設計遞迴演算法模式先求解問題的遞迴模型。在設計遞迴演算法的時候,如果糾結遞迴樹的每乙個...