针对无向图
因为Floyd是按照结点的顺序更新最短路的,所以我们在更新最短路之前先找到一个连接点k,当前的点k肯定不存在于已存在的最短路f[i][j]的路径上,因为我们还没用这个k去更新最短路,相当于 (i -> k -> j -> j到i的最短路 -> i)这样一个环就找到了,接下来我们要记录路径,用path[i][j]表示在最短路i到j的路径上j的前一个结点,所以我们在更新最短路时也要更新这个点,原来的最短路是i -> j,现在变成了 i -> k -> j,所以有per[i][j] = pre[k][j],因为要找最小环,所以不断更新找到环的权值,环更新一次,路径也要更新一次,路径更新时根据pre数组迭代一下就ok了
附上图片加深理解
1 #include <bits/stdc++.h> 2 #define read read() 3 #define up(i,l,r) for(register int i = (l);i <= (r);i++) 4 #define down(i,l,r) for(register int i = (l);i >= (r);i--) 5 #define traversal_vedge(i) for(register int i = head[u]; i ;i = e[i].nxt) 6 #define ll long long 7 using namespace std; 8 int read 9 { 10 int x = 0, f = 1; char ch = getchar(); 11 while(ch < 48 || ch > 57) {if(ch == '-')f = -1; ch = getchar();} 12 while(ch >=48 && ch <=57) {x = 10 * x + ch - 48;ch = getchar();} 13 return x * f; 14 } 15 void write(int x) 16 { 17 if(x < 0) x = -x,putchar('-'); 18 if(x > 9) write(x/10); 19 putchar(x%10 + 48); 20 } 21 //------------------------------------------------- 22 const int N = 105,INF = 0xfffffff;//debug 1e9+7 -> 0xffffff//极大值要开大 23 int n,m; 24 int f[N][N],e[N][N],pre[N][N],path[N]; 25 //f ,e 26 int min_ring,cnt; 27 void init() 28 { 29 up(i,1,n) 30 up(j,1,n) 31 { 32 f[i][j] = INF; 33 e[i][j] = INF; 34 pre[i][j] = i;//i -> j最短路径上j的前一个节点; 35 //初始化; 36 } 37 } 38 39 void readdata() 40 { 41 n = read; m = read; 42 init(); 43 up(i,1,m) 44 { 45 int u = read,v = read, w = read; 46 f[u][v] = f[v][u] = e[u][v] = e[v][u] = min(w,f[u][v]); 47 //重边中取最小; 48 } 49 } 50 51 void floyd() 52 { 53 min_ring = INF; 54 up(k,1,n) 55 { 56 //求环 57 up(i,1,k-1)//k不在i->j上;//这里的k是与i,j相连的; 58 { 59 up(j,1,i-1) //无向图利用对称性//? 60 { 61 if(f[i][j] + e[i][k] + e[k][j] < min_ring) 62 { 63 min_ring = f[i][j] + e[i][k] + e[k][j]; 64 cnt = 0; 65 int tmp = pre[i][j]; 66 while(tmp != i) 67 { 68 path[++cnt] = tmp; 69 tmp = pre[i][tmp]; 70 } 71 path[++cnt] = i; 72 path[++cnt] = k; 73 path[++cnt] = j; 74 } 75 } 76 } 77 //------------------------ 78 //求最短路;//这里的k是中转点(在i->j的最短路上) 79 up(i,1,n) 80 up(j,1,n) 81 { 82 if(f[i][k] + f[k][j] < f[i][j]) 83 { 84 f[i][j] = f[i][k] + f[k][j]; 85 //pre[i][j]表示i到j最短路径上j前面的一个点 86 //所以此时i到j的最短路径上j前一个点为k到j最短路径上j的前一个点 87 pre[i][j] = pre[k][j]; 88 } 89 } 90 } 91 } 92 93 void write_ans() 94 { 95 if(min_ring == INF) printf("No solution. "); 96 else up(i,1,cnt) write(path[i]),putchar(' '); 97 } 98 99 int main() 100 { 101 freopen("input.txt","r",stdin); 102 readdata(); 103 floyd(); 104 write_ans(); 105 return 0; 106 }