深入解析最短路徑演算法
正文第一節 問題的提出及解決方法
所謂最短路徑問題,能夠說有兩種情況來描寫敘述。
描寫敘述一:在圖論中,指的是尋找圖中兩個節點之間的最短距離。例如以下圖
描寫敘述二:在現實生活中,指的是找到從乙個地方到還有乙個地方的近期距離。例如以下圖
上述兩種情況的本質是一樣的,即求乙個點到還有乙個點的最短路徑。好了,問題已經提出來了,那怎麼解決呢?解決該問題的方法還是比較多的,只是因為各個路徑演算法所相應的問題條件不同,我們可依據不同的情況,選擇不同的路徑演算法。
本文將介紹三種最短路徑演算法,各自是:戴克斯特拉演算法(dijkstra algorithm),弗洛伊德演算法(floyd algorithm)以及a*搜尋演算法。
第二節 戴克斯特拉演算法(dijkstra algorithm)
該演算法解決的是有向圖中單個源點到其它頂點的最短路徑問題。
戴克斯特拉演算法的實現步驟例如以下:
第一步:用帶權的矩陣weiarcs來表示帶權有向圖,假設圖中的兩個頂點vi和vj是連通的,則用weiarcs[i][j]表示這兩個頂點所形成邊的權值;假設vi和vj不連通,即這條邊不存在,那麼將weiarcs[i][j]置為∞。
第二步:設s為已求得的從某一頂點v始發的最短路徑的終點的集合,且s的初始狀態為空,初始化時,將始發頂點置於s集合中。那麼從v出發到圖中其餘各個頂點vi可能達到的最短路徑長度的初值為d[i]。
第三步:選擇一頂點vj,使得vj就是當前求得的一條從頂點v出發的最短路徑的終點。此時令s = s ∪ 。
第四步:改動從v出發到集合v-s(v為圖頂點的集合)中任一頂點vk可達的最短路徑長度。假設d[j]+weiarcs[j][k] < d[k],則d[k] = d[j] + weiarcs[j][k]。
第五步:反覆操作第三步、第四步共n-1次,由此就能求得從v出發到圖中其餘各個頂點的最短路徑。
好了,實現過程就是這樣。只是光有文字描寫敘述不行,要更直白的表達這個過程,我覺得用影象表述是乙個非常好的選擇。例如以下圖所看到的
從運算過程表中,我們可知v0到其餘個點的最短路徑,例如以下圖
上述過程描寫敘述的戴克斯特拉演算法的**例如以下:
int shortpath(mgraph g,int v0,pathmatrix &p,shortpathtable &d) }
d[v0] = 0;final[v0] = true; //初始化,v0頂點屬於s集合
//開始主迴圈,每次求得v0到某個頂點v的最短路徑,並將v加到s集合中
for(i = 1; i < g.vexnum; i++) //其餘g.vexnum - 1個頂點
}} final[v] = true; //離v0頂點近期的v增加到s中
for(w = 0;w < g.vexnum;w++) //更新當前最算路徑及距離
}} return 0;
}
ok,dijkstra algorithm介紹完了。
第三節 弗洛伊德演算法(floyd algorithm)
該演算法解決的是有向帶權圖中兩頂點之間最短路徑的問題。
弗洛伊德演算法的設計步驟例如以下:
用帶權的矩陣weiarcs來表示帶權有向圖,假設圖中的兩個頂點vi和vj是連通的,則用weiarcs[i][j]表示這兩個頂點所形成邊的權值;假設vi和vj不連通,即這條邊不存在,那麼將weiarcs[i][j]置為∞。
要求:求節點vi到節點vj的最短路徑。
設d(i,j,k)為從節點vi到節點vj的以vk(vk∈(0,1,...k))節點為中間節點的最短路徑的長度。比如:從vi到vj這條路徑上經過節點vm和節點vk,那麼可表示為:vi-->vm-->vk-->vj。
那麼,就有:1.若最短路徑經過節點vk,則d(i,j,k) = d(i,k,k-1) + d(k,j,k-1);
2.若最短路徑不經過節點vk,則d(i,j,k) = d(i,j,k-1)。
所以,求的vi到vj的最短路徑可表示為:
d(i,j,k) = min(d(i,k,k-1) + d(k,j,k-1), d(i,j,k-1))。
老辦法,圖示的步驟例如以下:
求解的過程見下圖:
上述過程描寫敘述的弗洛伊德演算法的**例如以下:
int shortpath(mgraph g,int v0,pathmatrix &p,shortpathtable &d)
} for(u = 0;u < g.vexnum;u++)
for(v = 0;v < g.vexnum;v++)
for(w = 0;w < g.vexnum;w++)
return 0;
}
第四節 a*搜尋演算法
a*搜尋演算法,俗稱a星演算法。這是一種在圖平面上,有多個節點的路徑,求出最低通過成本的演算法。經常使用於遊戲中的npc的移動計算,或線上遊戲的bot的移動計算上。該演算法像dijkstra演算法一樣,能夠找到一條最短路徑;也像bfs一樣,進行啟示式的搜尋。
a*演算法最核心的部分,就在於它的乙個估值函式的設計上:f(n)=g(n)+h(n)。當中,g(n)表示從起始點到任一點n的實際距離,h(n)表示隨意頂點n到目標頂點的估算距離,f(n)是每乙個可能試探點的估值。這個估值函式遵循下面特性:
•假設h(n)為0,僅僅需求出g(n),即求出起點到隨意頂點n的最短路徑,則轉化為單源最短路徑問題,即dijkstra演算法;
•假設h(n)<=「n到目標的實際距離」,則一定能夠求出最優解。並且h(n)越小,須要計算的節點越多,演算法效率越低。
我們能夠這樣來描寫敘述:從出發點(startpoint,縮寫成sp)到終點(endpoint,縮寫成ep)的最短距離是一定的,於是我們能夠寫乙個估值函式來預計出發點到終點的最短距離。假設程式嘗試著從出發點沿著某條線路移動到了路徑上的還有乙個點(otherpoint,縮寫成op),那麼我們覺得這個方法所得到的從sp到ep間的預計距離為:從sp到op實際已走的距離加上預計函式估出的從op到ep的距離。如此,不管我們的程式搜尋展開到哪一步,都會得到乙個預計值,每一次決策後,將評估值和等待處理的方案一起排序,然後挑出待處理的各個方案中最有可能是最短路線的一部分的方案展開到下一步, 一直迴圈直到物件移動到目的地,或全部方案都嘗試過,卻沒有找到一條通向目的地的路徑則結束。
a*搜尋演算法的**過程請看:
第五節 相關說明
參考資料:資料結構(嚴蔚敏)、維基百科之a*搜尋演算法
第六節 結束語
想想,寫寫,畫畫......
零零散散的筆記
最近聽課的內容,雖然不全面。static void main string args 主函式 裝箱轉換 允許將值型別隱式轉換為引用型別 建立float型別,應使用f字尾 convert 將乙個基本資料型別轉換為另乙個基本資料型別 是求餘數 i 是i 1,先賦值,後運算 i是i 1,先運算,後賦值 i...
零零散散的問題
1.無法從 const char 7 轉換為 lpcwstr ans 工程使用了unicode字符集,把你的 字串 包含的字串修改為 t 字串 或者不使用unicode字符集即可 例如 abc.lpszclassname fb2009 應該改為 abc.lpszclassname t fb2009 ...
零零散散學演算法之詳解幾種最短路徑
深入解析最短路徑演算法 正文第一節 問題的提出及解決方法 所謂最短路徑問題,可以說有兩種情況來描述。描述一 在圖論中,指的是尋找圖中兩個節點之間的最短距離。如下圖 描述二 在現實生活中,指的是找到從乙個地方到另乙個地方的最近距離。如下圖 上述兩種情況的本質是一樣的,即求乙個點到另乙個點的最短路徑。好...