#10072. 「一本通 3.2 例 1」Sightseeing Trip(floyd求最小环+路径)

https://loj.ac/problem/10072

针对无向图

因为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.\n");
 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 }

猜你喜欢

转载自www.cnblogs.com/mzg1805/p/10407220.html