Floyd 算法求多源最短路徑

本文連接:http://www.cnblogs.com/Ash-ly/p/5920953.htmlhtml

Floyd算法:c++

  Floyd算法用來找出每對頂點之間的最短距離,它對圖的要求是,既能夠是無向圖也能夠是有向圖,邊權能夠爲負,可是不能存在負環(可根據最小環的正負來斷定).算法

基本算法:數組

  Floyd算法基於動態規劃的思想,以 u 到 v 的最短路徑至少通過前 k 個點爲轉移狀態進行計算,經過 k 的增長達到尋找最短路徑的目的.當 k 增長 1 時,最短路徑要麼不邊,若是改變,必通過第 k 各點,也就是說當起點 u 到第 k 個點的最短距離加上第 k 個點到終點 v 的最短路徑小於不通過第 k 個節點的最優最短路經長度的時候更新 u 到 v 的最短距離. 當 k = n 時, u 到 v 的最短路徑就肯定了. spa

僞代碼:3d

  圖的存儲用鄰接矩陣 gra[][] 來記錄,若是 u 與 v 之間沒有邊直接相連,則 gra[u][v] = INF; dist[][] 記錄最終的最短路. pre[i][j] 存儲 i 到 j 路徑中 i 的後一個節點.code

  1): 初始化:將 gra 中的數據複製到 dist 中做爲每對頂點間的最短路的初值, pre[i][j] = j;htm

  2): k 從 1 到 n 循環 n 次, 每次循環中枚舉圖中不一樣的兩點 u, v, 若是 dist[u][v] > dist[u][k] + dist[k][v], 則更新 dist[u][v] = dist[u][k] + dist[k][v], 更新 pre[u][v] = pre[u][k].blog

  3): 最後 dist[u][v] 數組中存儲的就是 u 到 v 的最短距離, u 到 v 的路徑, 則能夠按照順序查找就行了.ci

以圖爲例:

有一個以下的無向圖, 「D」數組存儲最短路值, 「P」 數組存儲最短路徑:

 

假設如今每對頂點之間的路徑只容許通過點 「1」 , 則更新後的每對頂點之間的距離:

 

這裏看到點 「2」 到點 「3」 的距離通過點 「1」 獲得了更新,同時更新了用於記錄路徑的 P 數組.

 

第二步,容許每對頂點之間的最短路徑通過點 「1」 和點 「2」,則更新後的數組爲:

 

能夠看到獲得更新的路徑爲:

1 ---> 4, 通過點 「2」 獲得更新

1 ---> 5, 通過點 「2」 獲得更新

3 ---> 5. 通過點 「1 --- > 2」 獲得更新

 

第三步: 容許通過點 「1」, 「2」 和點 「3」 則更新後的數組爲:

 

這則說明,上一步的最短路徑不須要更新.

 

第四步, 容許通過點 「1」, 「2」 , 「3」 和點 「4」 則更新後的數組爲:

 

能夠看到 3 ---> 5 的路徑通過點 「4」 獲得了更新(原先是 3 ---> 1 ---> 2 ---> 5, w = 9)

 

第五步, 容許任意兩點之間的最短路徑能夠通過所有點,則更新後的數組爲:

此次獲得更新的路徑爲:

1 ---> 4 的路徑. 更新爲 「1 ---> 2 ---> 5 ---> 4, w = 5」 (原路徑爲 1 ---> 2 ---> 4, w = 7)

2 ---> 3 的路徑. 更新爲 「2 ---> 5 ---> 4 ---> 3, w = 7」 (原路經爲 2 ---> 1 ---> 3, w = 8)

2 ---> 4 的路徑. 更新爲 「2 --> 5 --> 4, w = 2」 (原路徑爲 2 ---> 4, w = 4)

無向圖反之亦然.

 

至此最短路徑就尋找完畢. dist[i][j] 數組裏面保存的就是 i 到 j 的最短距離.若是要查尋路徑, 則按照查數組 pre 就好.好比查詢 「2」 到 「3」 的路徑:

則尋找     pre[2][3] = 5,  2 ---> 5

繼續尋找  pre[5][3] = 4,  2 ---> 5 ---> 4

繼續尋找  pre[4][3] = 3, 2 ---> 5 ---> 4 ---> 3

因爲此時 i = j = 3, 則 「2」 到 「3」 的最短路徑已找到爲: 2 ---> 5 ---> 4 ---> 3

 

代碼( 時間複雜度O(N3) ):

 1 #include <bits/stdc++.h>
 2 
 3 typedef long long LL;
 4 const int MAXN = 100;
 5 const int INF = 0x3f3f3f3f;
 6 using namespace std;
 7 
 8 int pre[MAXN + 3][MAXN + 3], dist[MAXN + 3][MAXN + 3]; //pre 儲存路徑; dist 存儲最短距離
 9 void floyd(int n, int gra[][MAXN + 3]) {
10     for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) dist[i][j] = gra[i][j], pre[i][j] = j;  //初始化
11     for(int k = 1; k <= n; k++) {   //嘗試通過 k 個點對每對頂點之間的距離進行更新
12         for(int i = 1; i <= n; i++) {
13             for(int j = 1; j <= n; j++) {
14                 if(dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j]) {
15                     dist[i][j] = dist[i][k] + dist[k][j];
16                     pre[i][j] = pre[i][k];
17                 }
18             }
19         }
20     }
21 }
22 
23 int pfpath(int u, int v) { //打印最短路徑
24     while(u != v) {
25         cout << u  << " ";
26         u = pre[u][v];
27     }
28     cout << u << endl;
29 }
30 
31 int gra[MAXN + 3][MAXN + 3];
32 int main() {
33     int n, m;
34     while(cin >> n >> m){ // n 個點,  m 條邊
35         for(int i = 0; i <= n; i++) for(int j = -1; j <= n; j++){
36             gra[i][j] = (i == j ? 0 : INF);
37         }
38         for(int i = 0; i < m; i++) {
39             int u, v, w; cin >> u >> v >> w;
40             gra[u][v] = gra[v][u] = w;  //無向圖
41         }
42         floyd(n, gra);
43     }
44     return 0;
45 }

 參考資料《圖論及應用》

相關文章
相關標籤/搜索