URAL1004 Sightseeing Trip Floyd 最小环

题意:求有权无向图的最小环,环至少包括三个点。

 

思路:

设map[i,j]表示i到j的的距离。输入有重边,在处理输入的时候只保存最短边。

取环中一个点k,左右点是ij则map[i,k]和map[k,j]是固定的不能变,可改变的是没有加入k点的i,j之间的最短路,设为dist[i,j]。那么最短环的长度表示为dist[i,j]+map[i,k]+map[k,j]。

Floyd的最外层循环为k时,最短路还没有用k和更新ij之间的最短路,恰好符合要求。所以在还没有用k更新ij之间的最短路之前更新环,每次更新环时更新路径即可。

 

算法步骤:

输入输出Floyd算法的框架,三个循环,在更新路径前更新环的最短路径。题解一和其他的题解(都是DP)代码很短,步骤很清晰,所以算法步骤粗略写写。

 

算法复杂度:

输入输出两个循环不超过O(n2),时间主要消耗在Floyd算法的框架里,三个n次循环,所以时间复杂度O(n3),最多是二维数组,空间复杂度是O(n2)

 

代码: 

 1 const int maxn=110; 
 2 int dist[maxn][maxn], map[maxn][maxn]; //最短距离,原图
 3 int pre[maxn][maxn]; // pre[i,j]记录最短路里,j前面一个点
 4 int path[maxn];      // 答案路径
 5 int n, m, num, minc; // num记录path里有多少个点,minc是最短环长度
 6  
 7 int main()
 8 {
 9     int  u, v, cost;
10 while(cin >> n && n){ 
11       if(n<0) break;
12         cin >> m; 
13         for(int i=1; i<=n; i++){
14             for(int j=1; j<=n; j++){
15                 dist[i][j]=map[i][j]=INF;
16                 pre[i][j]=i;
17             }
18       }
19       for(int i=1; i<=m; i++){
20           scanf("%d %d %d",&u,&v,&cost);
21           if(dist[u][v]>cost)   //重边
22               map[u][v]=map[v][u]=dist[u][v]=dist[v][u]=cost;
23       } 
24     // floyd
25     minc=INF;
26 for(int k=1; k<=n; k++){
27 // k还没加入(i,j)最短路,更新最短环
28         for(int i=1; i<k; i++){
29             for(int j=i+1; j<k; j++){
30                 int  ans=dist[i][j]+map[i][k]+map[k][j];
31                 if(ans<minc){  //找到最优解
32                     minc=ans;
33                     num=0;
34                     int p=j;
35                     while(p!=i){  //逆向寻找前驱遍历的路径并将其存储起来
36                         path[num++]=p;
37                         p=pre[i][p];
38                     }
39                     path[num++]=i;
40                     path[num++]=k;
41                 }
42             }
43         }
44         //用k更新i到j的最短路径
45         for(int i=1; i<=n; i++){
46             for(int j=1; j<=n; j++){
47                 if(dist[i][j]>dist[i][k]+dist[k][j]){
48                     dist[i][j]=dist[i][k]+dist[k][j];
49                     pre[i][j]=pre[k][j];
50                 }
51             }
52         }
53     }// end Floyd 
54     if(minc==INF) puts("No solution.");
55     else{
56         printf("%d",path[0]);
57         for(int i=1; i<num; i++)
58             printf(" %d",path[i]);
59         puts("");
60      }
61 }
62    return 0;
63 }

 

posted @ 2015-12-14 05:43  y丫t  阅读(405)  评论(0编辑  收藏  举报