1. 程式人生 > 其它 >Dijkstra和Floyd演算法遍歷圖的核心

Dijkstra和Floyd演算法遍歷圖的核心

  1. Dijkstra(迪傑斯特拉)演算法

    1. 解決的問題

    使用者指定一個頂點\(V_k\),求出\(V_i|_1^N\)\(V_k\)的最短路徑及其長度。

    1. 演算法的核心

    說到底它是一種“貪心演算法”,通過在每一步做出區域性最優決策來解決問題,希望找到全域性最小值。

    通俗地說就是:我們只有按照“從\(V_k\)出發找相鄰的頂點,然後挑個最短的\(V_{\min1}\),並找離其最短的\(V_{\min2}\)”這樣的方法尋找時,才可能得到最短路徑。這是我們尋找最短路徑的必要條件

    \[\min\norm{\overrightarrow{V_kV_i}}=\min\norm{\overrightarrow{V_kV_{\min1}}}+\cdots+\min\norm{\overrightarrow{V_{\min M-1}V_i}}=\sum_{j=\min1}^{\min M}\min\norm{\overrightarrow{V_{j-1}V_{j}}} \]

    這就是將所有的區域性最短相加,期望

    得到一個全域性最短。但是這樣顯然是不嚴謹的,因為很可能出現兩邊之和大於第三邊的情況,故而需要增加判定條件(必要轉充要的轉化條件)

    \[\norm{\overrightarrow{V_kV_i}}= \norm{\overrightarrow{V_kV_i}} \le \norm{\overrightarrow{V_kV_{\min j}}}+\norm{\overrightarrow{V_{\min j}V_i}} \ ?\ \norm{\overrightarrow{V_kV_i}} \ :\ \norm{\overrightarrow{V_kV_{\min j}}}+\norm{\overrightarrow{V_{\min j}V_i}} \]

    如果增加了一箇中轉點之後路徑變小了則將中轉點填入最短路徑計算中,否則維持原路徑。這個中轉點的確定依據是:當前離\(V_k\)

    最近的頂點\(V_{\min j}\)(為了滿足必要條件),正因為這一規則[1],我們每研究一箇中轉點\(V_{\min j}\)便可以確定\(\min\norm{\overrightarrow{V_kV_{\min j}}}\),這一步的貪心(剪枝)也造成了該演算法的侷限性[2]

    【註釋[1]】如果存在另一箇中轉點使得\(\norm{\overrightarrow{V_kV_{\min j}}}\)不是最小,則說明該中轉點\(V_{TP}\)\(V_k\)的距離小於\(V_{\min j}\)\(V_k\)的距離,即\(\norm{\overrightarrow{V_kV_{\min j}}} \gt \norm{\overrightarrow{V_kV_{TP}}}\)

    ,這顯然與\(V_{\min j}\)的定義相矛盾。

    【註釋[2]】在註釋1中我們假設了所有的權值都是正數,當權值出現負數時這個矛盾將不成立,成為Dijkstra演算法的侷限性之一。

    1. 演算法的描述

    Dijkstra演算法圖文詳解和C++程式碼

    1. 如何手算做題

    1. 時間複雜度為\(O(N^2)=O(\norm{V}^2)\)(鄰接矩陣),\(O(\log_{2}\norm{{V}}\times\norm{E})\)(堆優化鄰接表)。
  2. Floyd(弗洛伊德)演算法

    1. 解決的問題

    可以解決Dijkstra演算法不能帶負權值的問題,並一口氣求了所有的點之間的最短距離。

    1. 演算法的核心

    與Dijkstra演算法的思想是差不多的,只是Floyd不貪了[1],不再假設所有的權值為正數,所以在確定中轉點的時候不會去找距離\(V_k\)最近的點了,而是很野蠻地指定某一個或幾個點作為中轉點\(V_{TP}\),將其代入Dijkstra演算法的轉化條件:(將每一個i都從1到N遍歷一遍,中轉點TP也是從1一直累積到N)

    \[\small{\norm{\overrightarrow{V_kV_i}}^{(TP)}= \norm{\overrightarrow{V_kV_i}}^{pre(TP)} \le \norm{\overrightarrow{V_kV_{TP}}}^{pre(TP)}+\norm{\overrightarrow{V_{TP}V_i}}^{pre(TP)} \ ?\ \norm{\overrightarrow{V_kV_i}} \ :\ \norm{\overrightarrow{V_kV_{TP}}}+\norm{\overrightarrow{V_{TP}V_i}}} \]

    如果中轉點可以使得兩目標點之間的距離縮小,那就將中轉點加入路徑集合,否則捨棄中轉點並保持不變。這樣也能保證區域性最優(區域性最短路徑)。剩下的看看書應該就能明白了。

    【註釋[1]】Dijkstra演算法與Floyd演算法的不同就在兩者選取中轉點的方式不同,剩下的動態規劃思想都是一致的。

    1. 演算法的實現