1. 程式人生 > >多元最短路-floyd算法

多元最短路-floyd算法

之前 art ble pla sso 程序 sdn pop copy

要獲得帶權圖中任意兩點之間的最短距離,可以通過多次調用求解單源最短路徑的算法來實現。但floyd算法來實現會更簡單。

算法步驟:

假設圖由鄰接矩陣存放,通過二維數組dis[maxN][maxN]給出一張有向或者無向圖,dis[i][j]代表i到j的距離,沒有直接連通的路徑的話就初始化為無限大,用代指無限大的極大數INF代替,但這裏需要防止出現溢出的情況,否則在程序執行後將出現結果錯誤。

然後進行relax操作,任意三個節點i,j,k,若dis[i][k]+dis[k][j]<dis[i][j],就令dis[i][j]=dis[i][k]+dis[k][j],這樣就完成了一次松弛,並且通過三層循環嵌套將最終求解多源最短路徑的問題。時間復雜度為O(n^3)。

代碼:

[cpp] view plain copy
  1. const int maxN=1005;
  2. const int INF=1e9;
  3. #define min(a,b) (a)<(b)?(a):(b)
  4. int dis[maxN][maxN];
  5. int N;
  6. void floyd(){
  7. for(int k=1;k<=N;k++){
  8. for(int i=1;i<=N;i++){
  9. for(int j=1;j<=N;j++){
  10. dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
  11. }
  12. }
  13. }
  14. }

dis數組初始情況:無向圖情況dis[i][j]=dis[j][i],無向圖的話dis[i][j]嚴格代表從 i 到 j 的距離,兩種情況中對於 i 和 j 中沒有路徑直連的情況都將dis[i][j]賦值為一個極大數INF代表無限大表示此路不通。

關於為什麽僅僅只需要通過三次循環就能找到任意兩個點之間的距離而不需要考慮任何次序。

原理

問題的最終解決實際上是有一個個子問題的解決而解決的,比如說某兩點間的最短路徑經過的節點依次是a1,a2,a3,a4,則a1~a4可以看成是a1~a2+a2~a4,最終變成是a1-a2+a2-a3+a3-a4,則這個問題的解決就變成了這四個節點的發現過程(發現理解為發現正確的最短路徑即取道這些節點會比之前的路徑更短並且是最短,具體體現就是dis[i][j]中的值最終確定不會再發生改變了),而a1-a2,a2-a3,a3-a4這幾條邊一開始就是對應節點間的最短路徑,也就是說這三組節點中任意一組間的最短距離就是其

初始的值在整個循環中這些值都不會再變小,否則就會與a1-a2-a3-a4為a1到a4的最短路徑的這個前提條件相矛盾。

並且當k=i時,會松弛所有實際最短路徑經過i的兩點間最短路徑,比如說當k=a2時,a1,a3將松弛為最短,由於a3與a4一開始就為最短,如果先松弛的是a1-a3再松弛a1-a4的話,a1-a4也將松弛為最短,不然的話在k=a3時a1-a4一定會被松弛為最短,不需要考慮k訪問節點的順序也就k=a2在前還是k=a3在前,結果相同,對於一條包含n個節點的路徑,k每經過一個節點ai必定會將ai-1~ai+1松弛為最短,其余則會被松弛一定程度直至最短。

如果把松弛至最短這個條件看成包含N個節點的圖中的一條邊的話,因為N個節點只需要N-1條邊就能連通,也就是說對於一條路徑最多松弛N-1次就能找到最短路徑,只要k經過了a1~an中的所有節點,a1-an一定會被松弛為最短也就找到了a1-an的最短路徑,k會遍歷完全部節點,顯然滿足條件。

上面的a1.....an是代指,a1並不代表編號為1的節點,不要被a1誤導。

也就是說在一次最外層的循環體中所有節點間最短路徑的求解是同時進行的,只是說任何兩對節點的最短距離出現的時間可能不同,但當循環結束完,所有的節點間的最短路徑已經求出。

完整示例(hdu-2544):

[cpp] view plain copy
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxN=1005;
  4. const int INF=1e9;
  5. #define min(a,b) (a)<(b)?(a):(b)
  6. int dis[maxN][maxN];
  7. int N;
  8. void floyd(){
  9. for(int k=1;k<=N;k++){
  10. for(int i=1;i<=N;i++){
  11. for(int j=1;j<=N;j++){
  12. dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
  13. }
  14. }
  15. }
  16. }
  17. int main(){
  18. int m,a,b,c;
  19. while(cin>>N>>m&&(N+m)){
  20. for(int i=0;i<=N;i++){
  21. for(int j=0;j<=N;j++){
  22. dis[i][j]=INF;
  23. }
  24. dis[i][i]=0;
  25. }
  26. for(int i=1;i<=m;i++){
  27. cin>>a>>b>>c;
  28. dis[a][b]=dis[b][a]=c;
  29. }
  30. floyd();
  31. cout<<dis[1][N]<<endl;
  32. }
  33. }

多元最短路-floyd算法