vijosP1046 观光旅游
【思路】
Floyd求解最小环。
【代码】
1 #include<iostream> 2 using namespace std; 3 4 const int maxn = 100+10; 5 const int INF=1e8; 6 int f[maxn][maxn],dist[maxn][maxn]; 7 int n,m,min_loop; 8 9 void Floyd() 10 { 11 min_loop=INF; 12 for(int k=1;k<=n;k++) 13 { 14 for(int i=1;i<k;i++) 15 for(int j=i+1;j<k;j++) 16 if(f[i][j]+dist[i][k]+dist[k][j]<min_loop) 17 min_loop=f[i][j]+dist[i][k]+dist[k][j]; 18 19 for(int i=1;i<=n;i++) 20 for(int j=1;j<=n;j++) 21 if(f[i][k]<INF && f[k][j]<INF) 22 f[i][j]=min(f[i][j],f[i][k]+f[k][j]); 23 } 24 } 25 26 int main() { 27 ios::sync_with_stdio(false); 28 while(cin>>n>>m) 29 { 30 for(int i=1;i<=n;i++) 31 { 32 f[i][i]=dist[i][i]=0; 33 for(int j=i+1;j<=n;j++) 34 f[i][j]=f[j][i]=dist[i][j]=dist[j][i]=INF; 35 } 36 int u,v,w; 37 for(int i=0;i<m;i++) { 38 cin>>u>>v>>w; 39 dist[u][v]=dist[v][u]=f[u][v]=f[v][u]=w; 40 } 41 Floyd(); 42 if(min_loop==INF) cout<<"No solution. "; 43 else cout<<min_loop<<" "; 44 } 45 return 0; 46 }
【参考代码及原理】
1 /* 2 *算法引入: 3 *求一个图G中的最小环路的朴素算法为:每次找到一条边,删除了求这两点之间的最短路径; 4 *若能求出,则这条最短路径与原来的边构成一个环,不过时间复杂度略高; 5 * 6 *算法思想; 7 *Floyd算法是按照顶点的编号增加的顺序更新最短路径的; 8 *如果存在最小环,则会在这个环中的点编号最大的那个点u更新最短路径之前发现这个环; 9 *即当点u被拿来更新i到j的最短路径的时候,可以发现这个闭合环路; 10 *发现的方法是,更新最短路径前,遍历i,j点对,一定会发现某对i到j的最短路径长度: 11 *dist[i][j]+map[j][u]+map[u][i]!=INF,这时s的i和j是当前环中挨着点u的两个点; 12 *因为在之前的最短路径更新过程中,u没有参与更新,所以dist[i][j]所表示的路径中不会有点u,即一定为一个环; 13 * 14 *如果在每个新的点拿来更新最短路径之前遍历i和j验证上面的式子,虽然不能遍历到所有的环; 15 *但是由于dist[i][j]是i到j点的最短路径m所以肯定可以遍历到最小的环; 16 * 17 *如果有负权环,则该算法失效,因为包含负环的图上,dist[i][j]已经不能保证i到j的路径上不会经过同一个点多次了; 18 * 19 *算法测试: 20 *PKU1734(Sightseeing trip) 21 */ 22 23 #include<iostream> 24 #include<cstring> 25 #include<cstdlib> 26 #include<queue> 27 #include<cstdio> 28 #include<climits> 29 #include<algorithm> 30 using namespace std; 31 32 const int N=111; 33 const int INF=0xffffff; 34 35 int min_loop; 36 int num; 37 int map[N][N],dist[N][N],pre[N][N]; 38 int path[N]; 39 int n,m; 40 41 void dfs(int i,int j) 42 { 43 int k=pre[i][j]; 44 if(k==0) 45 { 46 path[num++]=j; 47 return; 48 } 49 dfs(i,k); 50 dfs(k,j); 51 } 52 53 void Floyd() 54 { 55 min_loop=INF; 56 memset(pre,0,sizeof(pre)); 57 for(int k=1; k<=n; k++) 58 { 59 for(int i=1; i<k; i++) //i<k 60 { 61 for(int j=i+1; j<k; j++) //j<k 62 { 63 if(dist[i][j]+map[i][k]+map[k][j]<min_loop) 64 { 65 min_loop=dist[i][j]+map[i][k]+map[k][j]; 66 num=0; 67 path[num++]=i; 68 dfs(i,j); 69 path[num++]=k; 70 } 71 } 72 } 73 74 for(int i=1; i<=n; i++) 75 { 76 for(int j=1; j<=n; j++) 77 { 78 if(dist[i][k]+dist[k][j]<dist[i][j]) 79 { 80 dist[i][j]=dist[i][k]+dist[k][j]; 81 pre[i][j]=k; 82 } 83 } 84 } 85 } 86 } 87 88 int main() 89 { 90 // freopen("C:\Users\Administrator\Desktop\kd.txt","r",stdin); 91 while(~scanf("%d%d",&n,&m)) 92 { 93 for(int i=1; i<=n; i++) 94 { 95 for(int j=i+1; j<=n; j++) 96 map[i][j]=map[j][i]=dist[i][j]=dist[j][i]=INF; 97 map[i][i]=dist[i][i]=0; 98 } 99 for(int i=0; i<m; i++) 100 { 101 int u,v,w; 102 scanf("%d%d%d",&u,&v,&w); 103 if(w<map[u][v]) 104 { 105 map[u][v]=map[v][u]=w; 106 dist[u][v]=dist[v][u]=w; 107 } 108 } 109 Floyd(); 110 if(min_loop==INF) 111 puts("No solution."); 112 else 113 { 114 for(int i=0; i<num-1; i++) 115 printf("%d ",path[i]); 116 printf("%d ",path[num-1]); 117 } 118 } 119 return 0; 120 }