Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม

Single-Source Shortest Paths, Arbitrary Weights (Bellman-Ford Algorithm)

Single-Source Shortest Path (Arbitrary Weights) หรือ Bellman-Ford Algorithm หาระยะทางต่ำสุดจาก Source Vertex ไปยังโหนดอื่นๆ รับน้ำหนักได้ทั้งบวกและลบ ต่างจาก Dijkstra ที่รับแค่บวก

Single-Source Shortest Paths, Arbitrary Weights (Bellman-Ford Algorithm)

Bellman-Ford หาระยะทางแบบ Bottom-up หาระยะทางที่มี 1 Edge ก่อน แล้วเพิ่มความยาว Path ทีละขั้น

Input

Cost Matrix ของกราฟ

0 6 ∞ 7 ∞ ∞
∞ 0 5 8 -4 ∞
-2 ∞ 0 ∞ ∞ ∞
∞ ∞ -3 0 9 2
∞ 7 ∞ ∞ 0

Output

Source Vertex: 2
Vert: 0 1 2 3 4
Dist: -4 -2 0 3 -6
Pred: 4 2 -1 0 1
The graph has no negative edge cycle

Algorithm

bellmanFord(dist, pred, source)

Input: Distance list, Predecessor list, Source vertex
Output: True ถ้าพบ Negative Cycle

Begin
    iCount := 1
    maxEdge := n * (n - 1) / 2
    for all vertices v do
        dist[v] := ∞; pred[v] := φ
    done
    dist[source] := 0
    eCount := number of edges
    create edge list edgeList
    while iCount < n do
        for i := 0 to eCount do
            if dist[edgeList[i].v] > dist[edgeList[i].u] + cost[u,v] then
                dist[edgeList[i].v] := dist[edgeList[i].u] + cost[u,v]
                pred[edgeList[i].v] := edgeList[i].u
            done
        done
        iCount := iCount + 1
    for all vertices i do
        if dist[edgeList[i].v] > dist[edgeList[i].u] + cost[u,v] then
            return true
        done
    return false
End

ตัวอย่างโค้ด (C++)

#include <iostream>
#include <iomanip>
#define V 5
#define INF 999
using namespace std;

int costMat[V][V] = {
    {0, 6, INF, 7, INF},
    {INF, 0, 5, 8, -4},
    {INF, -2, 0, INF, INF},
    {INF, INF, -3, 0, 9},
    {2, INF, 7, INF, 0}
};

typedef struct { int u, v, cost; } edge;

int bellmanFord(int *dist, int *pred, int src) {
    int icount = 1, ecount, max = V*(V-1)/2;
    edge edgeList[max];
    for(int i = 0; i < V; i++) {
        dist[i] = INF; pred[i] = -1;
    }
    dist[src] = 0;
    ecount = makeEdgeList(edgeList);
    while(icount < V) {
        for(int i = 0; i < ecount; i++)
            if(dist[edgeList[i].v] > dist[edgeList[i].u] + costMat[edgeList[i].u][edgeList[i].v]) {
                dist[edgeList[i].v] = dist[edgeList[i].u] + costMat[edgeList[i].u][edgeList[i].v];
                pred[edgeList[i].v] = edgeList[i].u;
            }
        icount++;
    }
    for(int i = 0; i < ecount; i++)
        if(dist[edgeList[i].v] > dist[edgeList[i].u] + costMat[edgeList[i].u][edgeList[i].v])
            return 1; // negative cycle
    return 0; // no negative cycle
}

int main() {
    int dist[V], pred[V], source = 2, report;
    report = bellmanFord(dist, pred, source);
    cout << "Source Vertex: " << source << endl;
    display(dist, pred);
    if(report) cout << "The graph has a negative edge cycle" << endl;
    else cout << "The graph has no negative edge cycle" << endl;
}

Output

Source Vertex: 2
Vert: 0 1 2 3 4
Dist: -4 -2 0 3 -6
Pred: 4 2 -1 0 1
The graph has no negative edge cycle