1、問題引入
帶權有向圖中單源點的最短路徑問題可以用地傑斯特拉算法求解,如果要求解圖中每一對頂點之間的最短路徑,類似可以想到的方法為:每次以一個頂點為源點,重復執行地傑斯特拉算法算法n次,這樣,便可以求得每一對頂點之間的最短路徑,總的執行時間為O(n3)。
這里可以采用另外一種求解算法:Floyd算法。
2、Floyd的基本思想為:
從鄰接矩陣a開始進行n次迭代,第一次迭代后a[i,j]的值是從vi到vj且中間不經過變化大於1的頂點的最短路徑長度;第k次迭代后a[i,j]的值是從vi到vj且中間不經過變化大於k的頂點的最短路徑長度 第n次迭代后a[i,j]的值就是從vi到vj的最短路徑長度。
3、算法描述:
(1) 用數組d[i][j]來記錄i,j之間的最短距離。初始化d[i][j],若i=j則d[i][j]=0,
若i,j之間有邊連接則d[i][j]的值為該邊的權值,否則d[i][j]的值為max 。
(2) 對所有的k值從1到n,修正任意兩點之間的最短距離,計算d[i][k]+d[k][j]的值,
若小於d[i][j],則d[i][j]= d[i][k]+d[k][j],否則d[i][j]的值不變。
4、具體實現:
帶權有向圖如下:
在2.txt文件中保存的帶權有向圖的數據為:
其中第一個數據4表述圖中有4個節點,其他的四行四列數據表示各個節點之間的路徑長度,9999表示兩個節點之間不可達。
具體代碼為:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #define max 9999 4 void Floyd(int,int **,int**,int**); 5 void Searchpath(int,int,int**,int**); 6 void main() 7 { 8 int i,j,num,first,last; 9 FILE *p; 10 p=fopen("2.txt","r"); 11 if(p==NULL) 12 { 13 printf("無法打開2.txt"); 14 exit(-1); 15 } 16 fscanf(p,"%d",&num);//獲取點的個數; 17 int **a=(int**)malloc(sizeof(int*)*num); 18 for(i=0;i<num;i++) 19 a[i]=(int*)malloc(sizeof(int)*num); 20 for(i=0;i<num;i++)//獲取圖中各個點之間的路徑長度; 21 for(j=0;j<num;j++) 22 fscanf(p,"%d",&a[i][j]); 23 //path[i][j]用於記錄從i到j的最短路徑上j點的前一個節點 24 int **path=(int**)malloc(sizeof(int*)*num); 25 for(i=0;i<num;i++) 26 path[i]=(int*)malloc(sizeof(int)*num); 27 //d[i][j]用於記錄從i到j的最短路徑的長度 28 int **d=(int**)malloc(sizeof(int*)*num); 29 for(i=0;i<num;i++) 30 d[i]=(int*)malloc(sizeof(int)*num); 31 //佛洛依德算法程序調用 32 Floyd(num,path,d,a); 33 printf("最終得到的距離矩陣為:\n"); 34 for(i=0;i<num;i++) 35 { 36 for(j=0;j<num;j++) 37 printf("%d ",d[i][j]); 38 printf("\n"); 39 } 40 printf("請輸入起始點(小於%d):",num); 41 scanf("%d",&first); 42 printf("\n請輸入終止點(小於%d):",num); 43 scanf("%d",&last); 44 printf("起始點%d到終止點%d的最短路徑長度為:%d\n",first,last,d[first][last]); 45 Searchpath(first,last,path,d);//利用path[i][j]得出從i到j的最短路徑 46 } 47 void Floyd(int num,int **path,int**d,int **a) 48 { 49 int i,j,k; 50 for(i=0;i<num;i++) 51 { 52 for(j=0;j<num;j++)//初始化 53 { 54 if(a[i][j]<max) path[i][j]=j;//從i到j有路徑 55 else path[i][j]=-1; 56 d[i][j]=a[i][j]; 57 } 58 } 59 for(k=0;k<num;k++) 60 for(i=0;i<num;i++) 61 for(j=0;j<num;j++) 62 if(d[i][j]>d[i][k]+d[k][j])//從i到j的一條更短的路徑 63 { 64 d[i][j]=d[i][k]+d[k][j]; 65 path[i][j]=path[i][k]; 66 } 67 } 68 void Searchpath(int first,int last,int **path,int**d) 69 { 70 int k; 71 if(d[first][last]==max) 72 printf("起始點%d到終止點%d不可達",first,last); 73 else 74 { 75 printf("起始點到終點的路徑為:"); 76 k=last; 77 printf("%d <-- ",k); 78 while((k!=first)&&(k!=path[first][k])) 79 { 80 k=path[first][k]; 81 printf("%d <-- ",k); 82 if(k==path[first][k]) 83 k=first; 84 } 85 printf("%d\n",first); 86 } 87 }
5、參考資料:
(1)嚴蔚敏,數據結構。