不同性質的圖中,所採取的策略有所不同,自然存在各樣的求最短路徑的演算法。
對於無向無權圖(也可以假設權值為1),就可以使用最基本的廣度優先搜尋演算法,從源點開始對整個圖進行搜尋,訪問到所有的點。因為廣度優先搜尋最先訪問到的是相鄰的點,所以距離最近的點最先訪問到,記錄的距離也就最小。
演算法偽**,時間複雜度為 $o(|v|+|e|)$。
for all u in v:
dist(u) = inf
dist(s) = 0
q = [s] (fifo 佇列)
while q is not empty:
u = eject(q)
for all edges (u,v) in e:
if dist(v) = inf:
inject(q, v)
dist(v) = dist(v)+1
dijkstra 演算法是基於廣度搜尋的單源最短路徑演算法,利用此演算法可以在無負邊的有向圖中求得一點到圖中其他點的最短路徑。演算法的基本思想是每個點記錄源點到其他點的距離,在從以按距離值大小排列的優先佇列中選取值最小的點,再更新相鄰點的距離值,直到隊列為空。
假設求點 s 到圖中其他點的最短路徑,$dist(u)$ 表示 s 到 u 的距離。 h 表示優先佇列。
dijkstra 演算法偽**表示如下
for all u in v:
dist(u) = inf
prev(u) = none
dist(s) = 0
h = makequeue(v) (using dist-values as keys)
while h is not empty:
u = deletemin(h)
for all edges (u, v) in e:
if dist(v) > dist(u) + l(u,v):
dist(v) = dist(u) + l(u,v)
prev(v) = u
decreasekey(h, v)
演算法總共涉及 $|v|$ 次佇列刪除操作,$|v|+|e|$ 次佇列插入和更新操作。如果優先佇列的實現是基於二叉堆(binary heap)則佇列插入和刪除操作時間演算法複雜度都為 $o(log|v|)$,演算法的時間複雜度為 $o((|v|+|e|)log|v|)$。
bellman-ford 演算法跟 dijkstra 演算法一樣都是單源最短路徑演算法,但是可以應用於存在負邊的有向圖中。dijkstra 演算法中最關鍵的步驟就是當前距離值最小的點根據到相鄰的點距離,更新相鄰點到源點的距離,被選出的距離值最小的點的距離值是成遞增關係。如果存在負邊則前面已經被選為距離值最小的點的值可能改變,變得更小,也就使得 dijkstra 演算法不適用。
dijkstra 演算法的關鍵步驟是更新點到源點的距離值,更新按照距離值遞增的順序。如果存在負邊就不能確保仍然按照這種遞增的順序更新,但最終仍是更新路徑上所有點的距離值直到不再改變。一條最短路徑最多經過|v|-1條邊,所以 bellman-ford 通過|v|-1次重複更新所有的邊,來確保更新是按照正確的順序進行。
如果圖中不存在負環,則|v|-1次更新後,所有點的距離值都達到最小,不會再改變。存在負環的話,再進行一次更新,有的點的距離值仍然會改變。通過這種方法也可以判斷圖中是否存在負環。
演算法偽**如下,時間複雜度 $o(|v|*|e|)$
for all u in v:
dist(u) = inf
prev(u) = none
dist(s) = 0
repeat |v|-1 times:
for all (u,v) in e:
dist(v) = min
對於乙個有向無環圖,可以通過深度優先搜尋獲得其線性化順序(linearised order),如下圖
dist(u)表示從源點 s 到 u 的最短距離。求上圖中的d點 的dist(d),則只要知道跟 d 相鄰並指向 d 的點的距離值(dist(b), dist(c)),通過比較取最小值:
$$ dist(d) = min\lbrace\rbrace$$
要求得到某個點的最短距離前,要先求得到所有指向該點的最短距離。求解乙個問題前,先要解決多個子問題,這也就利用了動態規範方法。
演算法的偽**如下,時間複雜度$o(|v|+|e|)$(dfs 獲得線性化順序的時間複雜度)。
for all u in v:
dist(u) = inf
dist(s) = 0
lv = dfs(s) # linearised order
for v in lv:
dist(v) = min
floyd-warshall 演算法是一種基於動態規劃的演算法,利用此演算法可以求得無負環有向圖中任意兩點間的最短路徑。
無負環圖中的點記為 $\lbrace\rbrace$,$dist(i,j,k)$ 表示 $i$ 到 $j$ 最短路徑長度,路徑經過的點只能是 $\lbrace\rbrace$ 集合中的。
如何從 k-1個點擴充套件到 k 個點?
k 個點中,從 i 到 j 的最短路徑只有兩種可能,經過 k 點或不經過。如果經過 k 點,則以 k 為中間點,$dist(i,j,k)$ 可以表示為 $dist(i,k,k-1)$ 和 $dist(k,j,j-1)$ 的和值,如下圖所示。
那麼 dist(i,j,k)的值就為兩條路徑中值最小的乙個。
$$min\lbrace\rbrace$$
演算法偽**表示如下,演算法時間複雜度$o(|v|^3)$
for i=1 to n:
for j=1 to n:
dist(i,j,0) = inf
for all (i,j) in e:
dist(i,j,0) = l(i,j)
for k=1 to n:
for i=1 to n:
for j=1 to n:
dist(i,j,k) = min
最短路徑演算法 最短路
在每年的校賽裡,所有進入決賽的同學都會獲得一件很漂亮的t shirt。但是每當我們的工作人員把上百件的衣服從商店運回到賽場的時候,卻是非常累的!所以現在他們想要尋找最短的從商店到賽場的路線,你可以幫助他們嗎?input 輸入包括多組資料。每組資料第一行是兩個整數n m n 100,m 10000 n...
單源最短路徑演算法小結
這裡就不寫具體演算法了,只將他們的時間複雜度 適用範圍 複雜程度簡單做個比較 待搜尋的圖都指有向圖 無向圖類似 儲存方式均為鄰接表 一 廣度優先搜尋 bfs 時間複雜度 o v e 效率很高 適用範圍 很窄 僅適於無權邊的圖。即每條邊長度都為1的情況 複雜程度 一般,需佇列 二 bellman fo...
最短路演算法小結
dijkstra演算法 適用於 無負權邊,無環 視所求得 最短 定義而論 的圖的單源最短路問題 也就是考慮乙個點 常用 dist i 陣列儲存源點 到 i 點的距離,應用貪心的思想,每次 從 未選 點集中 選出距離已選點集最近 最優 的乙個點,然後將此點加入已選點集,嘗試通過此點 更新 源點 到未選...