【算法系列学习】Dijkstra算法变形 [kuangbin带你飞]专题四 最短路练习

https://vjudge.net/contest/66569#problem/B

类试题:noip2013 货物运输

           POJ 1797 Heavy Transportation

方法一:Dijkstra变形

http://blog.csdn.net/u013446688/article/details/42777173

关键在于对松弛的变形,这里不是求源点到每个点的所有路径中的路径长度最小值,而是求源点到每个点的所有路径中Frog distance(路径中的最大距离)的最小值

所以dis[k]=min(dis[k],dis[v]+map[v][k])变成了dis[k]=min(dis[k],max(dis[v],map[v][k]))

这里的dis[k]不再是源点到结点k所有路径中路径长度的最小值,而是源点到结点k所有路径中Frog distance(路径中的最大距离)的最小值。

为了理解dis[k]=min(dis[k],max(dis[v],map[v][k])),我们可以做这样的假设:源点到v的路径有三条,这三条路径的frog distance分别是3,4,5;那么dis[v]就是3。

现在分两种情况分别进行讨论:

1.map[v][k]>dis[v],由于源点经过v到达k的路径也有三条,这三条的frog distance就分别变成了map[v][k],max(4,map[v][k]),max(5,map[v][k]);那么dis[k]就一定是最小值map[v][k].

2.map[v][k]<=dis[v],则这三条路径的frog distance 还是3,4,5.dis[k]就等于dis[v]

下面是AC的代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<algorithm>
 6 #include<cmath>
 7 const double inf=0x3f3f3f3f;
 8 using namespace std;
 9 int n;
10 struct node
11 {
12     int x,y;
13 }nd[203];
14 double map[203][203];
15 double dist(node a,node b)
16 {
17     return sqrt((double)(a.x-b.x)*(a.x-b.x)+(double)(a.y-b.y)*(a.y-b.y));
18 }
19 double dis[203];
20 void Dijkstra()
21 {
22     bool vis[203];
23     memset(vis,0,sizeof(vis));
24     dis[1]=0.0;
25     for(int i=2;i<=n;i++)
26     {
27         dis[i]=inf;
28     }
29     int v;
30     for(int i=1;i<=n;i++)
31     {
32         int m=inf;
33         for(int k=1;k<=n;k++)
34         {
35             if(!vis[k]&&dis[k]<m)
36             {
37                 m=dis[k];
38                 v=k;        
39             }
40         }
41         vis[v]=1;
42         //对以v为顶点的边进行松弛 
43         for(int k=1;k<=n;k++)
44         {
45             if(!vis[k])
46             {
47                 dis[k]=min(dis[k],max(dis[v],map[v][k])); 
48             }
49         }
50     }
51 }
52 int main()
53 {
54     int kas=1;
55     while(scanf("%d",&n)&&n)
56     {
57         for(int i=1;i<=n;i++)
58         {
59             scanf("%d%d",&nd[i].x,&nd[i].y);
60             for(int k=1;k<i;k++)
61             {
62                 map[i][k]=map[k][i]=dist(nd[i],nd[k]);
63             }
64         }
65         Dijkstra();
66         if(kas!=1)
67         {
68             printf("
");
69         }
70         printf("Scenario #%d
",kas++);
71         printf("Frog Distance = %.3f
",dis[2]);
72     }
73     return 0;
74 }
Dijkstra

 要注意四点:

1.sqrt()要强制转化为double

2.double不能用memset(dis,inf,sizeof(dis))

3.

for(int k=1;k<=n;k++)
{
  if(!vis[k])
  {
    dis[k]=min(dis[k],max(dis[v],map[v][k]));
  }
}

不写vis[k]也对,但是增加时间复杂度

4.注意输入输出,最后一个样例之后是没有空行的

方法二:二分+并查集

http://xwk.iteye.com/blog/2129453

二分出一个mid值表示最大边的长度,然后遍历所有边,只要当前边的长度不超过mid,就合并当前边所连接的两个点。最后判断1和2在不在同一个连通分量上,如果是则说明当前mid已经足够,为了找到mid的最小值,R=mid.

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<algorithm>
 6 #include<cmath>
 7 
 8 using namespace std;
 9 const int maxn=2e2+10;
10 const double eps=1e-7;
11 int n;
12 struct node
13 {
14     int x,y;
15 }nd[maxn];
16 double map[maxn][maxn];
17 double dist(const node& a,const node& b)
18 {
19     return sqrt((double)(a.x-b.x)*(a.x-b.x)+(double)(a.y-b.y)*(a.y-b.y));
20 }
21 int fa[maxn];
22 int find(int i)
23 {
24     if(fa[i]==-1)
25     {
26         return i;
27     }
28     return fa[i]=find(fa[i]);
29 }
30 bool bind(int i,int k)
31 {
32     i=find(i);
33     k=find(k);
34     if(i!=k)
35     {
36         fa[i]=k;
37     }
38     return true;
39 }
40 bool ok(double mid)
41 {
42     memset(fa,-1,sizeof(fa));
43     //加进去的边的最大值为mid 
44     for(int i=1;i<=n;i++)
45     {
46         for(int k=i+1;k<=n;k++)
47         {
48             if(map[i][k]<mid)
49             {
50                 bind(i,k);
51             }
52         }
53     }
54     return find(1)==find(2);
55 }
56 
57 int main()
58 {
59     int kas=1;
60     while(scanf("%d",&n)&&n)
61     {    
62         for(int i=1;i<=n;i++)
63         {
64             scanf("%d%d",&nd[i].x,&nd[i].y);
65             for(int k=1;k<i;k++)
66             {
67                 map[i][k]=map[k][i]=dist(nd[i],nd[k]);
68             }
69         }
70         double l=0.0;
71         double r=map[1][2];
72         while(r-l>eps)
73         {
74             double mid=(l+r)/2;
75             if(ok(mid))
76             {
77                 r=mid;
78             }
79             else
80             {
81                 l=mid;
82             }
83         }
84         if(kas!=1)
85         {
86             printf("
");
87         }    
88         printf("Scenario #%d
",kas++);
89         printf("Frog Distance = %.3f
",r); 
90     }
91     return 0;
92 }
二分+并查集

注意在ok函数里,每次都要初始化memset(fa,-1,sizeof(fa));

方法三:最小生成树

http://blog.csdn.net/shouwang_tomorrow/article/details/47616983

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<algorithm>
 6 #include<cmath>
 7 
 8 using namespace std;
 9 int n;
10 int cnt;
11 const int maxn=2e4+10;
12 
13 
14 
15 struct edge
16 {
17     int x,y;
18     double w;
19 }e[maxn];
20 struct node
21 {
22     int x;
23     int y;
24 }nd[203];
25 double dist(const node& a,const node& b)
26 {
27     return sqrt((double)(a.x-b.x)*(a.x-b.x)+(double)(a.y-b.y)*(a.y-b.y));
28 }
29 bool cmp(const edge& a,const edge& b)
30 {
31     return a.w<b.w;
32 }
33 int fa[maxn];
34 int find(int i)
35 {
36     if(fa[i]==-1)
37     {
38         return i;
39     }
40     return fa[i]=find(fa[i]);    
41 }
42 bool bind(int i,int k)
43 {
44     i=find(i);
45     k=find(k);
46     if(i!=k)
47     {
48         fa[i]=k;
49         return true;    
50     }
51     return false;
52 }
53 double Kruskal()
54 {
55     for(int i=0;i<cnt;i++)
56     {
57         if(bind(e[i].x,e[i].y))
58         {
59             if(find(1)==find(2))
60             {
61                 return e[i].w;
62             }
63         }    
64     }
65 }
66 int main()
67 {
68     int kas=1;
69     while(scanf("%d",&n)&&n)
70     {
71         cnt=0;
72         for(int i=1;i<=n;i++)
73         {
74             scanf("%d%d",&nd[i].x,&nd[i].y);
75             for(int k=1;k<i;k++)
76             {
77                 e[cnt].x=i;
78                 e[cnt].y=k;
79                 e[cnt++].w=dist(nd[i],nd[k]);
80             }
81         }
82         sort(e,e+cnt,cmp);
83         memset(fa,-1,sizeof(fa));
84         double ans=Kruskal();
85         if(kas!=1)
86         {
87             printf("
");
88         }
89         printf("Scenario #%d
Frog Distance = %.3f
",kas++,ans);
90     }
91     return 0;
92 }
Kruskal
原文地址:https://www.cnblogs.com/itcsl/p/6666223.html