圖的最短路徑演算法彙總

Tech In Pieces發表於2020-11-30

這種題目在圖裡面也不算非常常見 但是一旦見到 這演算法就很明顯 所以看到這種題目就應該立刻想到最短路徑演算法 然後需要立刻定位到自己需要用的那種演算法。不然雖然知道最短路徑演算法 但是不知道要選擇哪個 就會十分慌亂 心態立刻就崩了。所以本文就回顧一下有哪些圖的最短路徑演算法,這些演算法的應用場景有哪些?我們經常遇見的問題有哪些種類?

經常遇見的問題總類:
確定起點 求最短路徑
確定終點 求最短路徑(跟確定起點的沒有區別)
確定起點終點的最短路徑
全域性最短路徑(即找到所有兩點之間的最短路徑 可以想象的到 最後要返回一個二維矩陣,matrix[i][j] represents for the shortest distance between the node i and the node j)

我們已知的圖的演算法有哪些?
在這裡插入圖片描述

dijkstra演算法:能夠解決單源最短路徑 即從某個固定的起點出發 到每個節點的最短路徑。此種演算法基於BFS,適用於(有向圖無向圖)(正權重)的圖
bellman-ford演算法:能夠解決單源最短路徑問題,同樣基於BFS 適用於(有向圖無向圖)
(正權重負權重)而且能夠解決存在負環的問題(因為負環一直走下去永遠最小)
floyd-warshall演算法:用來解決全域性最短路徑問題 最大的特點就是他的三個for 這個程式碼也是非常簡單的,而且也能解決有負權邊的問題
所以綜上所述 不能夠解決負權環問題的只有Dijkstra演算法。

下面詳細的來說一下這三個演算法:
dijkstra演算法:
假設我們用鄰接表來表示頂點之間的關係(有權重或者無權重)然後要用一個陣列dis表示起始地點到其他各個頂點的距離,這個是我們要維護和最後輸出的,初始化為正無窮。
用通俗的話來說這個演算法 就是從起點開始 在起點向外擴的邊中 尋找最短的路徑 就把那個節點也一併拉過來 然後看看這兩個節點組成的圖 與外界連結的所有的邊中 最短的是哪個,然後再把那個節點拉過來。就這樣一直拉一直拉 直到所有的節點都被拉過來。說白了 就是一個從一個節點出發 不斷擴張的過程。
bellman-ford: (沒搞太明白)
Bellman-ford 演算法比dijkstra演算法更具普遍性,因為它對邊沒有要求,可以處理負權邊與負權迴路。缺點是時間複雜度過高,高達O(VE), V為頂點數,E為邊數。

for (var i = 0; i < n - 1; i++) {
    for (var j = 0; j < m; j++) {//對m條邊進行迴圈
      var edge = edges[j];
      // 鬆弛操作
      if (distance[edge.to] > distance[edge.from] + edge.weight ){ 
        distance[edge.to] = distance[edge.from] + edge.weight;
      }
    }
}

floyd-warshall演算法:
基本思想特別簡單 就是我們想找從i到j的最短路徑 那麼任意節點都可以作為中間節點,就算是i或者j節點也可以。
而整個演算法所基於的公式,就是下面這個(i到j的最短路徑兩種可能 要麼經過k 要麼不經過k)

d[i][j] = min(d[i][j], d[i][k] + d[k][j]);

但是我們要注意,這裡的迴圈是kij而不是ijk,具體為什麼參見本博主其他文章。

不要忘了bellman-ford這個演算法,前半部分Richard Bellman是動態規劃的提出者。

相關文章