posts - 43,  comments - 9,  trackbacks - 0
最近做了两道floyd变种的题目,又加深了对floyd原理的理解.

第1题: bupt 1460 游览路线
http://acm.cs.bupt.cn/onlinejudge/showproblem.php?problem_id=1460
大意是给定一个无向图,找出一个环,使得环的长度最短,并且这个环上至少有3个顶点.

一种O(mn^2)的做法是枚举每条边<u,v>,用dijkstra求由原图删去这条边后的新图中u,v间最短路径dist[u,v],该环长度即为map[u,v]+dist[u,v].输出环长度值最小的那个.

仔细分析知道,这题实际上是要求每对点u,v间不包含边<u,v>的最短路径.想到floyd正是计算所有点对最短路径的.但是这里不能包含边<u,v>的条件就是变化所在.

floyd的原理是依次往"中间点集"中加入点k,再更新任意点对dist[i,j].
此题中,如果直接枚举map[i,k]+map[k,j]+floyd[i,j](floyd[i,j]为使用经典算法得到的两点间最短路),有可能出现一个点经过两次的情况.比如由边集{(1,2),(1,3),(1,4)}构成的图,依题意是无解,但是用错误的枚举方法却有解.原因是没有排除(1->2),(2->1->3),(3->1)的情况.此时可以看出,以点k为原点枚举i,j时的floyd[i,j]应该是保证不经过k的,也就是枚举操作应该在往"中间点集"中加入k之前!
这样可以得出算法的大致轮廓:在加入点k前更新dist[i,j]
但是问题是,此时的中间点只有1..k-1,那后面的点k+1..n会不会漏处理呢?
本质上,这题求的是环的长度,而不是路径长度.因此,假如存在一个更短的环,它路径上有k之后的点p1,p2,...,pm,设其中最后处理的那个点是pl.那么这个环一定会在向中间点集中加入pl的那次循环里枚举到.
因此不存在漏解问题.

代码如下:
 1 #include <iostream>
 2 using namespace std;
 3 int N,M,ans;
 4 //w是原图矩阵,d是floyd最短路矩阵
 5 int w[110][110],d[110][110];
 6 int main(){
 7     int i,j,k,a,b,c;
 8     while(scanf("%d%d",&N,&M)!=EOF){
 9         for(i=1;i<=N;i++)
10             for(j=1;j<=N;j++)
11                 w[i][j]=d[i][j]=0;
12         for(i=1;i<=M;i++){
13             scanf("%d%d%d",&a,&b,&c);
14             if(!w[a][b]||c<w[a][b]){
15                 w[a][b]=w[b][a]=c;
16                 d[a][b]=d[b][a]=c;
17             }
18         }
19         ans=0x7fffffff;
20         for(k=1;k<=N;k++){
21             //先枚举map[i,k]+map[k,j]+floyd[i,j]
22             for(i=1;i<k;i++)
23                 for(j=i+1;j<k;j++)
24                     if(w[i][k]&&w[k][j]&&d[i][j])
25                         ans=min(ans,d[i][j]+w[i][k]+w[k][j]);
26             //再向中间点集中加入k并更新floyd矩阵
27             for(i=1;i<=N;i++){
28                 if(!d[i][k])continue;
29                 for(j=1;j<=N;j++){
30                     if(!d[k][j]||i==j)continue;
31                     if(!d[i][j]||d[i][j]>d[i][k]+d[k][j])
32                         d[i][j]=d[i][k]+d[k][j];
33                 }
34             }
35         }
36         if(ans<0x7fffffff)
37             printf("%d\n",ans);
38         else
39             puts("No solution.");
40     }
41     return 0;
42 }


posted on 2009-03-31 14:20 wolf5x 阅读(159) 评论(0)  编辑 收藏 引用 所属分类: acm_icpcalgorithm

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2009年3月>
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

"Do not spend all your time on training or studying - this way you will probably become very exhausted and unwilling to compete more. Whatever you do - have fun. Once you find programming is no fun anymore – drop it. Play soccer, find a girlfriend, study something not related to programming, just live a life - programming contests are only programming contests, and nothing more. Don't let them become your life - for your life is much more interesting and colorful." -- Petr

留言簿(3)

随笔分类(59)

随笔档案(43)

cows

搜索

  •  

最新评论

评论排行榜