最短路徑之迪傑斯特拉(Dijkstra)算法

對於網圖來講,最短路徑,是指兩頂點之間通過的邊上權值之和最少的路徑,而且咱們稱路徑上的第一個頂點爲源點,最後一個頂點爲終點。最短路徑的算法主要有迪傑斯特拉(Dijkstra)算法和弗洛伊德(Floyd)算法。本文先來說第一種,從某個源點到其他各頂點的最短路徑問題。html

這是一個按路徑長度遞增的次序產生最短路徑的算法,它的大體思路是這樣的。node

初始時,S中僅含有源。設u是G的某一個頂點,把從源到u且中間只通過S中頂點的路稱爲從源到u的特殊路徑,並用數組dist記錄當前每一個頂點所對應的最短特殊路徑長度。Dijkstra算法每次從V-S中取出具備最短特殊路長度的頂點u,將u添加到S中,同時對數組dist做必要的修改。一旦S包含了全部V中頂點,dist就記錄了從源到全部其它頂點之間的最短路徑長度.ios

好比說要求圖7-7-3中頂點v0到v1的最短路徑,顯然就是1。因爲頂點v1還與v2,v3,v4連線,因此此時咱們同時求得了v0->v1->v2 = 1+3 = 4, v0->v1->v3 = 1 +7 = 8, v0->v1->v4 = 1+5 = 6。算法

如今咱們能夠知道v0到v2的最短距離爲4而不是v0->v2 直接連線的5,如圖7-7-4所示。因爲頂點v2還與v4,v5連線,因此同時咱們求得了v0->v2->v4其實就是v0->v1->v2->v4 = 4+1=5,v0->v2->v5 = 4+7 = 11,這裏v0->v2咱們用的是剛纔計算出來的較小的4。此時咱們也發現v0->v1->v2->v4 = 5要比v0->v1->v4 = 6還要小,因此v0到v4的最短距離目前是5,如圖7-7-5所示。數組

當咱們要求v0到v3的最短路徑時,通向v3的三條邊,除了v6沒有研究過外,v0->v1->v3 = 8, 而v0->v4->v3 = 5 +2 = 7,所以v0到v3的最短路徑爲7,如圖7-7-6所示。spa

如上所示,這個算法並非一會兒就求出來v0到v8的最短路徑,而是一步步求出它們之間頂點的最短距離,過程當中都是基於已經求出的最短路徑的基礎上,求得更遠頂點的最短路徑,最終獲得想要的結果。code

#include <iostream>
using namespace std; const int maxnum = 100; const int maxint = 999999; // 各數組都從下標1開始
int dist[maxnum];     // 表示當前點到源點的最短路徑長度
int prev[maxnum];     // 記錄當前點的前一個結點
int c[maxnum][maxnum];   // 記錄圖的兩點間路徑長度
int n, line;             // 圖的結點數和路徑數 // n -- n nodes // v -- the source node // dist[] -- the distance from the ith node to the source node // prev[] -- the previous node of the ith node // c[][] -- every two nodes' distance
void Dijkstra(int n, int v, int *dist, int *prev, int c[maxnum][maxnum]) { bool s[maxnum];    // 判斷是否已存入該點到S集合中
    for(int i=1; i<=n; ++i) { dist[i] = c[v][i]; s[i] = 0;     // 初始都未用過該點
        if(dist[i] == maxint) prev[i] = 0; else prev[i] = v; } dist[v] = 0; s[v] = 1; // 依次將未放入S集合的結點中,取dist[]最小值的結點,放入結合S中 // 一旦S包含了全部V中頂點,dist就記錄了從源點到全部其餘頂點之間的最短路徑長度 // 注意是從第二個節點開始,第一個爲源點
    for(int i=2; i<=n; ++i) { int tmp = maxint; int u = v; // 找出當前未使用的點j的dist[j]最小值
        for(int j=1; j<=n; ++j) if((!s[j]) && dist[j]<tmp) { u = j;              // u保存當前鄰接點中距離最小的點的號碼
                tmp = dist[j]; } s[u] = 1;    // 表示u點已存入S集合中 // 更新dist
        for(int j=1; j<=n; ++j) if((!s[j]) && c[u][j]<maxint) { int newdist = dist[u] + c[u][j]; if(newdist < dist[j]) { dist[j] = newdist; prev[j] = u; } } } } // 查找從源點v到終點u的路徑,並輸出
void searchPath(int *prev,int v, int u) { int que[maxnum]; int tot = 1; que[tot] = u; tot++; int tmp = prev[u]; while(tmp != v) { que[tot] = tmp; tot++; tmp = prev[tmp]; } que[tot] = v; for(int i=tot; i>=1; --i) if(i != 1) cout << que[i] << " -> "; else cout << que[i] << endl; } int main() { freopen("input.txt", "r", stdin); // 各數組都從下標1開始 // 輸入結點數
    cin >> n; // 輸入路徑數
    cin >> line; int p, q, len;          // 輸入p, q兩點及其路徑長度 // 初始化c[][]爲maxint
    for(int i=1; i<=n; ++i) for(int j=1; j<=n; ++j) c[i][j] = maxint; for(int i=1; i<=line; ++i) { cin >> p >> q >> len; if(len < c[p][q])       // 有重邊
 { c[p][q] = len;      // p指向q
            c[q][p] = len;      // q指向p,這樣表示無向圖
 } } for(int i=1; i<=n; ++i) dist[i] = maxint; for(int i=1; i<=n; ++i) { for(int j=1; j<=n; ++j) printf("%8d", c[i][j]); printf("\n"); } Dijkstra(n, 1, dist, prev, c); // 最短路徑長度
    cout << "源點到最後一個頂點的最短路徑長度: " << dist[n] << endl; // 路徑
    cout << "源點到最後一個頂點的路徑爲: "; searchPath(prev, 1, n); }

輸入數據:
5
7
1 2 10
1 4 30
1 5 100
2 3 50
3 5 10
4 3 20
4 5 60
輸出數據:
999999 10 999999 30 100
10 999999 50 999999 999999
999999 50 999999 20 10
30 999999 20 999999 60
100 999999 10 60 999999
源點到最後一個頂點的最短路徑長度: 60
源點到最後一個頂點的路徑爲: 1 -> 4 -> 3 -> 5
htm

參考:http://tech.ddvip.com/2013-06/1371580493197421.htmlblog

http://www.wutianqi.com/?p=1890ip

相關文章
相關標籤/搜索