單源最短路:Bellman-Ford算法 及 證明


 

描述:

求圖中某一點到其他任一點的最短距離。

操作:

1. 初始化

結果保存在一個dist數組里,源點的結果初始化為0,其他初始化為無窮大(如INT32_MAX)。

2. 計算:

兩重for循環,第一層,迭代n - 1次(n為節點數);

      第二層,遍歷每條邊,如果其源點對應的距離加上邊權重小於終點對應距離,則更新終點最短距離;

3. 判斷負權環:

當步驟二計算完時,遍歷左右邊,看是否存在某條邊(u, v),有d[u] + w(u, v) < d[v],即還可以更新,如存在則存在負權環。

證明:

求最短路證明:

一。假設某點與源點不連通。

由於初始化時,除了源點距離初始為0之外,其他點都初始化為無窮大,如果不連通,則某點所在的連通圖的任一條邊都不會導致更新。

二。假設x點與源點連通。

每個點都存在自己的最短路,為(e0, e1, e2, ..., ek)。

顯然,源點只要經過n - 1條邊就可到達任一點;  (一)

現只需證明,對x點,每次迭代(松弛),至少有一條最短邊ei的距離被找到,除非已經到達x點。  (二)

  對於第一次迭代,必定更新和源點相連的所有邊(如果是有向圖,則是指出去的),由於源點距離是0,和其相連的都是無窮大。

    而這些往外連的邊中,必有一條是x點的最短路上起始的一條邊。

  則設有點k,這個點是x最短路上的一個點,下一次松弛,必能找到下一個點,且也是x的最短路上的一個點:

    由於下一次松弛將更新與k相連的所有點。

有(一)(二)可得,上面兩次迭代可以找出最短路。

而關於負權環的判斷:

由於負權環的存在,可以通過不斷繞着走從而減小環上各個點的距離。

所以即使迭代完成,當判斷是否還能更新時,會發現還是可以更新的,這就判斷了存在負權環。

代碼:

簡單輸出最短路,如果要路徑可以為每個節點儲存一個最后一次訪問的節點,逆向遍歷一遍即可得到路徑。

#include <string>
#include <iostream>
#include <vector>
using namespace std;

struct Edge {
    int start;
    int end;
    int weight;
};

bool BellmanFord() {
    int source = 0;
    int vex_num, edge_num;
    cout << "Input the number of vertexs and edges:" << endl;
    cin >> vex_num >> edge_num;

    vector<int> dist(vex_num, INT32_MAX);
    dist[source] = 0;

    vector<Edge> e;
    for (int i = 0; i < edge_num; i++) {
        Edge et;
        cin >> et.start >> et.end >> et.weight;
        e.push_back(et);
    }

    for (int i = 0; i < vex_num - 1; i++)
        for (int j = 0; j < edge_num; j++)
            if (dist[e[j].start] + e[j].weight < dist[e[j].end] && dist[e[j].start] != INT32_MAX)
                dist[e[j].end] = dist[e[j].start] + e[j].weight;

    for (int i = 0; i < dist.size(); dist++)
        cout << dist[i] << endl;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM