全源最短路径之弗洛伊德算法(C语言)
Floyd(弗洛伊德)算法
該算法是解決任意兩點間的最短路徑的一種算法,可以正確處理有向圖或負權(但不可存在負權回路)的最短路徑問題,同時也被用于計算有向圖的傳遞閉包。
時間復雜度為 O(N^3)
空間復雜度為 O(N^2)
Floyd算法蘊涵了動態(tài)規(guī)劃的思想,
簡單說:從任意節(jié)點i到任意節(jié)點j的最短路徑存在兩種可能
所以,我們假設Dis(i,j)為節(jié)點u到節(jié)點v的最短路徑的距離,對于每一個節(jié)點k,我們檢查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,證明從i到k再到j的路徑比i直接到j的路徑短,我們便設置Dis(i,j) = Dis(i,k) + Dis(k,j),這樣一來,當我們遍歷完所有節(jié)點k,Dis(i,j)中記錄的便是i到j的最短路徑的距離。
Floyd算法適用于APSP(All Pairs Shortest Paths,多源最短路徑),是一種動態(tài)規(guī)劃算法,稠密圖效果最佳。此算法簡單有效,由于三重循環(huán)結構緊湊,對于稠密圖,效率要高于Dijkstra算法
優(yōu)點:容易理解,可以算出任意兩個節(jié)點之間的最短距離,代碼編寫簡單。
缺點:時間復雜度比較高,不適合計算大量數據。
算法代碼如下:
void Floyd(AdjMatrix *G) {int A[MaxVertices][MaxVertices],path[MaxVertices][MaxVertices];int i,j,k;//初始化for (i=0;i<G->numV;i++){for (j=0;j<G->numV;j++){A[i][j]=G->Edge[i][j];path[i][j]=-1;}} //三重循環(huán),floyd算法核心for (k=0;k<G->numV;k++){for (i=0;i<G->numV;i++){for (j=0;j<G->numV;j++){if (A[i][j]>A[i][k]+A[k][j]){A[i][j]=A[i][k]+A[k][j];path[i][j]=k;}}}}Dispath(A,path,G->numV);//輸出函數 }輸出函數包括兩部分
void Ppath(int path[][MaxVertices],int i,int j) {int k;k=path[i][j];if (k==-1){return;}Ppath(path,i,k);printf("%d->",k);Ppath(path,k,j); }void Dispath(int A[][MaxVertices],int path[][MaxVertices],int n) {int i,j;for (i=0;i<n;i++){for (j=0;j<n;j++){if (A[i][j]==INF){if (i!=j){printf("從%d到%d沒有路徑\n",i,j);}}else{printf(" 從%d到%d的最短路徑長度為:%d ",i,j,A[i][j]);printf("路徑:%d->",i);Ppath(path,i,j);//兩點i,j之間還有其他中繼結點,則循環(huán)套用次函數printf("%d\n",j);}}} }具體代碼如下:
#include<stdio.h> #include<stdlib.h> #define MaxVertices 100 //假設包含100個頂點 #define MaxWeight 32767 //不鄰接時為32767,但輸出時用 "∞" #define MAXV 10 #define INF 32767 typedef struct{ //包含權的鄰接矩陣的的定義char Vertices[MaxVertices]; //頂點信息的數組int Edge[MaxVertices][MaxVertices]; //邊的權信息的數組int numV; //當前的頂點數int numE; //當前的邊數 }AdjMatrix;void CreateGraph(AdjMatrix *G) //圖的生成函數 { int n,e,vi,vj,w,i,j;printf("請輸入圖的頂點數和邊數(以空格分隔):");scanf("%d%d",&n,&e);G->numV=n;G->numE=e;for(i=0;i<n;i++) //圖的初始化for(j=0;j<n;j++){ if(i==j)G->Edge[i][j]=0;else G->Edge[i][j]=32767;}for(i=0;i<n;i++)for(i=0;i<G->numV;i++) //將頂點存入數組中{ printf("請輸入第%d個頂點的信息(整型):",i+1); // G->adjlist[i].vertex=getchar(); scanf(" %c",&G->Vertices[i]);}printf("\n");for(i=0;i<G->numE;i++){ printf("請輸入邊的信息i,j,w(以空格分隔):");scanf("%d%d%d",&vi,&vj,&w); //若為不帶權值的圖,則w輸入1//若為帶權值的圖,則w輸入對應權值G->Edge[vi-1][vj-1]=w;//①G->Edge[vj-1][vi-1]=w;//②//無向圖具有對稱性的規(guī)律,通過①②實現//有向圖不具備此性質,所以只需要①} } void DispGraph(AdjMatrix G) //輸出鄰接矩陣的信息 { int i,j;printf("\n輸出頂點的信息(整型):\n");for(i=0;i<G.numV;i++)printf("%8c",G.Vertices[i]);printf("\n輸出鄰接矩陣:\n");printf("\t");for(i=0;i<G.numV;i++)printf("%8c",G.Vertices[i]);for(i=0;i<G.numV;i++){ printf("\n%8d",i+1);for(j=0;j<G.numV;j++){ if(G.Edge[i][j]==32767) //兩點之間無連接時權值為默認的32767,但輸出時為了方便輸出 "∞"printf("%8s", "∞");elseprintf("%8d",G.Edge[i][j]);}printf("\n"); } } void Ppath(int path[][MaxVertices],int i,int j) {int k;k=path[i][j];if (k==-1){return;}Ppath(path,i,k);printf("%d->",k);Ppath(path,k,j); }void Dispath(int A[][MaxVertices],int path[][MaxVertices],int n) {int i,j;for (i=0;i<n;i++){for (j=0;j<n;j++){if (A[i][j]==INF){if (i!=j){printf("從%d到%d沒有路徑\n",i,j);}}else{printf(" 從%d到%d的最短路徑長度為:%d ",i,j,A[i][j]);printf("路徑:%d->",i);Ppath(path,i,j);//兩點i,j之間還有其他中繼結點,則循環(huán)套用次函數printf("%d\n",j);}}} } void Floyd(AdjMatrix *G) {int A[MaxVertices][MaxVertices],path[MaxVertices][MaxVertices];int i,j,k;//初始化for (i=0;i<G->numV;i++){for (j=0;j<G->numV;j++){A[i][j]=G->Edge[i][j];path[i][j]=-1;}} //三重循環(huán),floyd算法核心for (k=0;k<G->numV;k++){for (i=0;i<G->numV;i++){for (j=0;j<G->numV;j++){if (A[i][j]>A[i][k]+A[k][j]){A[i][j]=A[i][k]+A[k][j];path[i][j]=k;}}}}Dispath(A,path,G->numV);//輸出函數 }int main() { AdjMatrix G;freopen("1.txt","r",stdin);CreateGraph(&G);Floyd(&G);DispGraph(G); }注:由于測試輸入數據較多,程序可以采用文件輸入
5 7
1
2
3
4
5
1 2 2
1 3 4
1 5 2
2 3 1
2 4 6
3 4 2
4 5 3
總結
以上是生活随笔為你收集整理的全源最短路径之弗洛伊德算法(C语言)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JSP的9个内置对象-response
- 下一篇: 图论算法(二)-最短路径的Dijkstr