多源最短路->Floyd演算法
阿新 • • 發佈:2019-01-05
//多源最短路 動態規劃,狀態轉移方程map[i,j]:=min{map[i,k]+map[k,j],map[i,j]} /* 能解決帶有負權邊的圖的最短路徑問題。 對於有向圖,負權還可以解決,負圈會呈現一定形式(記住:任何演算法,帶有負圈的最短路徑是無解的)。 對於無向圖,取的測試樣例中有負邊,最後結果很奇葩,然後圖不變,邊的值不變,只是改變點的編號,圖中有的兩點間的最短距離結果竟然不同...... 所以對於有負權/負圈的圖的最短路徑問題,還是很難處理的 其實無向圖中若有負權,演算法過程會在負權那裡轉圈,就像負圈一樣 */ //有向圖 此處的儲存路徑方法不適用於負圈(執行出錯) #include <cstdio> #include <cstring> #include <iostream> using namespace std; #define MAXN 100 #define INFINITY 0X7FFFFFFF int map[MAXN][MAXN]; int path[MAXN][MAXN]; int n,m; void Init(){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i!=j){ map[i][j]=INFINITY; } else{ map[i][j]=0;}path[i][j]=0; } } } } void PrintPath(int x,int y){ if(path[x][y]){ PrintPath(x,path[x][y]); cout<<" to "; } cout<<y; } void Floyd(){for(int t=1;t<=n;t++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(map[i][t]!=INFINITY&&map[t][j]!=INFINITY&&map[i][j]>map[i][t]+map[t][j]){ map[i][j]=map[i][t]+map[t][j]; path[i][j]=t; } } } } int main(){ int x,y,w;cin>>n>>m; Init(); for(int i=1;i<=m;i++){ cin>>x>>y>>w; map[x][y]=w; path[x][y]=x; } Floyd(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ printf("%d%c",map[i][j],j==n?'\n':' '); } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ printf("%d%c",path[i][j],j==n?'\n':' '); } } cin>>x>>y;//起始PrintPath(x,y); return 0; } /*負圈測試:3 31 3 73 2 -52 1 -10 */ //有向圖 此程式碼可列印負圈路徑 #include <stdio.h> #include <stdlib.h> #define max 1000000000 int d[1000][1000],path[1000][1000]; int main(){ int i,j,k,m,n; int x,y,z; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=n;j++){ d[i][j]=max; path[i][j]=j; } for(i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); d[x][y]=z; } for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++){ if(d[i][k]+d[k][j]<d[i][j]){ d[i][j]=d[i][k]+d[k][j]; path[i][j]=path[i][k]; } } for(i=1;i<=n;i++) for(j=1;j<=n;j++) printf("%d%c",d[i][j],j==n?'\n':' '); int f,en; scanf("%d%d",&f,&en); do{ printf("%d->",f); f=path[f][en]; }while(f!=en); printf("%d\n",en); return 0; } //path[i][j]為從i到j最短路徑下一步走哪裡 //此處path原理為當前點先到下一個點,再去處理下一個點到終點的路徑,path[下一個點][j]為下一個點到j最短路徑下一步走哪裡 //每一步保證是最短的(貪心),最後也肯定是最短路徑 //無向圖 全是正的正常,有負的就亂套:數不一樣,有負的就打印不出來 #include <cstdio> #include <cstring> #include <iostream> using namespace std; #define MAXN 100 #define INFINITY 0X7FFFFFFF int map[MAXN][MAXN]; int path[MAXN][MAXN]; int n,m; void Init(){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i!=j){ map[i][j]=INFINITY; } else{ map[i][j]=0; } path[i][j]=0; } } } void PrintPath(int x,int y){ if(path[x][y]){ PrintPath(x,path[x][y]); cout<<" to "; } cout<<y; } void Floyd(){ for(int t=1;t<=n;t++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(map[i][t]!=INFINITY&&map[t][j]!=INFINITY&&map[i][j]>map[i][t]+map[t][j]){ map[i][j]=map[i][t]+map[t][j]; path[i][j]=t; } } } } } int main(){ int x,y,w; cin>>n>>m; Init(); for(int i=1;i<=m;i++){ cin>>x>>y>>w; map[x][y]=map[y][x]=w; path[x][y]=x; } Floyd(); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ printf("%d%c",map[i][j],j==n?'\n':' '); } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ printf("%d%c",path[i][j],j==n?'\n':' '); } } cin>>x>>y;//起始 PrintPath(x,y); return 0; } //無向圖 全是正的正常,有負的就亂套:數不一樣,有負的/負圈能打印出來,但不符合 #include <stdio.h> #include <stdlib.h> #define max 1000000000 int d[1000][1000],path[1000][1000]; int main(){ int i,j,k,m,n; int x,y,z; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=n;j++){ d[i][j]=max; path[i][j]=j; } for(i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); d[x][y]=d[y][x]=z; } for(k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++){ if(d[i][k]+d[k][j]<d[i][j]){ d[i][j]=d[i][k]+d[k][j]; path[i][j]=path[i][k]; } } for(i=1;i<=n;i++) for(j=1;j<=n;j++) printf("%d%c",d[i][j],j==n?'\n':' '); int f,en; scanf("%d%d",&f,&en); do{ printf("%d->",f); f=path[f][en]; }while(f!=en); printf("%d\n",en); return 0; }