zoukankan      html  css  js  c++  java
  • 【算法系列学习】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
  • 相关阅读:
    好文章集合
    WPF:布局
    xcode6.0 模拟器打不开
    vue-vux初学
    【个人笔记】《知了堂》MySQL三种关系:一对一,一对多,多对多。
    vue-axios跨域配置
    vue+webpack使用
    vs code插件
    echarts图表属性设置
    【个人笔记】《知了堂》ajax的get及post请求
  • 原文地址:https://www.cnblogs.com/itcsl/p/6666223.html
Copyright © 2011-2022 走看看