Single-source Shortest Path | All-pairs Shortest Path | ||||
---|---|---|---|---|---|
演算法 | DAG | Dijkstra | Bellman-Fold | Floyd-Warshall | Johnson |
策略 | 利用 tolopological sort | greedy | DP | DP | Dijkstra + Bellman-Fold |
可否有 cycle | X | O | O | O | O |
可否有negative cost edge | O | X | O | O | O |
可否有negative cycle length | X | X | X | X | X |
給定 為一 directed weighted graph,其 weight function 為
令 為 path 上所有邊之權重和,稱之為 之權重
Tip
給定起點 (source vertex),如何求 到各點之最短路徑,此即 single-source shortest path problem
Note
給定 為 root 是 的 tree 且 是 之子圖,若 , 中 到 的路徑皆為 上 到 的最短路徑,則稱 為 shortest path tree
在 shortest path tree 中 之 parent (predecessor of ) 記作
, 表示 到 之 shortest path esimate,在最短路徑演算法中,此值會被不斷更新,直到演算法執行結束時方為 到 之最短路徑長
定義幾個副程式
先調整一下 Graph
:
在 DAG 上可以在 linear time 找出 shortest path
關鍵在於使用 topological sort
Time complexity:
另外,在 DAG 上求最長路徑 (又稱 critical path) 有至少兩種 linear time 的作法:
relax
裡面所有 改成 並把 改成 Dijkstra's algorithm 的精神就是 greedy
課本上原本的作法是會準備一個空集合 用來蒐集已經計算出最短距離的頂點
每次 完,將 加入其中 ()
不過這不影響到演算法本身的表達
Dijkstra 最重要的靈魂就在於那個 priority queue
我們使用該資料結構來每回合選出 shortest path estimate 最小的頂點
本演算法的時間複雜度會受選擇怎樣的資料結構來作為 priority queue 影響:
演算法中的 while
執行次數為 ,故
我們可以整理一下 Dijkstra 中各步驟的時間複雜度,該演算法很重要:
\ | Total | |||
---|---|---|---|---|
Array | ||||
Binary Heap | ||||
Fibonacci Heap |
Warning
Dijkstra's algorithm 有個限制,那就是圖上不允許有負邊
如果圖上有負邊,則會使此問題不具備 greedy choice property,故使 Dijkstra's algorithm 無法保證求出正確答案
例如下圖情況:
由 到 的最短路徑應該是 <, , >,但使用 Dijkstra 計算出的 shortest path tree 卻為:
這邊可是超重要考點
指的是:假設 <> 為 到 的最短路徑,依 的順序做 ,過程中可穿插圖上其他邊之 ,則最終 之 shortest path estimate 必為 到 之最短路徑長
這邊要證明,可以利用數學歸納法
我懶,就不寫證明出來了,但建議讀者在腦中想過一遍,要是真的考出來也要寫幾個字就能開始掰完整段證明 (這就是數學歸納法)
讀者如果仔細看 Dijkstra's Algo,如果覺得很像 BFS,表示你對圖遍歷之思考有了不同的思考,恭喜
該演算法的核心在於為每一輪圖上每條邊作
我們採用 DP 的策略,定義 表示 走不超過 條邊到達 之 shortest path length
由上圖可知,我們在比的就是直接從 走到 比較短?還是中間多經過些點的路徑比較短?
表示成遞迴關係式:
在演算法的寫法中,Bellman-Ford 還有個額外的功能,那就是能找出 negative cycle length
上述寫法的時間複雜度是
negative cycle 會使最短路徑問題不 well-defined (在負環上越繞路徑越短,那你一輩子繞圈不就好了),所以任何最短路徑問題的演算法都不允許圖上有負環
不過跟 Dijkstra 不一樣,Bellman-Ford 能夠允許圖上有負邊
解釋為何上面的演算法可以偵測負環:
這裡用到的,正是大家早就學過的三角不等式
此三角不等式成立 中不含 可達之負環
:
若 使得
令 為 到 之最短路徑則 再加上 形成 到 之路徑 ,且
此與 為 到 之最短距離矛盾,故三角不等式成立
:
假設 <> 為 可達之 cycle,其中
中不含 可達之負環
那如果你只是要用 DP 的寫法,以下是 的寫法:
DP 基本只要能寫出遞迴式,就能寫出 code
這是一題看似跟圖論無關,但卻能用 Bellman-Ford 解出來的題目
交大 102 的資演: (試題來源)
我們可以建立 constraint graph 配上 weight function
其中 對應
讓 到各頂點的距離為 ,而上面的不等式就當作對應兩頂點的距離
如果 Bellman-Ford 偵測出負環,此系統無解;若沒有,則我們會得出一組解,加上常數 即通解
圖如下:
對圖使用 Bellman-Ford algorithm
顧名思義,其實就是 single-source 但變成每個頂點都當過 source
如過圖沒有負邊,那我們就對每個頂點做 Dijkstra 就好 (做 次),時間複雜度頂多
如果要能處理負邊而使用 Bellman-Ford 呢?那時間複雜度會是
那有沒有能處理負邊又在 的演算法呢?有的。
Floyd-Washall 也是採用 DP 策略
給定 為不含有負環的有向圖, , 為 weight function
使用 adjacency matrix 來表示圖,其中
再定義 , 為 到 之某個最短路徑中 的 predecessor
若 為路徑 中的某點但不為兩端點,則稱 為 之 intermediate vertex (中繼點)
令 為 到 且途中只允許經過 之最短路徑 的長度:
經過上述討論,我們可以整理出 之遞迴關係式:
而計算 predecessor 之遞迴關係式:
例如給你一張圖:
執行演算法的過程應該會是:
考試時沒辦法打 code 讓電腦執行,所以值得記憶如何加速手寫操作
上圖中螢光筆標記的代表下回合依舊保持不變的部份,我們計算剩下的部份就好
這樣看會快很多
Floyd-Warshall 可以拿來解遞移閉包的問題,改一下就好:
我們處理的就會變成是關係矩陣
這邊比較是離散的內容,詳細可見這裡
例題可以參考 LeetCode 1462. Course Schedule IV
Floyd-Warshall 的確厲害,但要是沒有負邊的話,感覺 Dijkstra 能有更好的表現
如果我們可以調整圖上的權重,使得圖上不存在負邊,那麼我們執行 次 Dijkstra 即可解 all-pairs shortest path problem 啦
為 sparse 且使用 Fibonacci heap 的話,此方法的時間複雜度比 Floyd-Warshall 更好
然而,此演算法困難也是其厲害的點,就在於如何 reweight
我們必須保證以下三點成立:
我們再用更數學的角度審視要滿足的條件
假設 為 directed weighted graph,其 weight function 為
令 為新的 weight function
假設 在 reweight 後的最短路徑為
定義 :
, 滿足:
我們目標是使
我們前面就知道了,在不含負環的情況下,三角不等式 必成立
所以我們的作法即在 中加入頂點 , 連到所有頂點,並且這些邊的 weight 皆為
必成立
所以我們就定義
Time complexity: