zoukankan      html  css  js  c++  java
  • 寒假Day7:最短路

    HDU2112-HDU Today-dijkstra

    题面:

    经过锦囊相助,海东集团终于度过了危机,从此,HDU的发展就一直顺风顺水,到了2050年,集团已经相当规模了,据说进入了钱江肉丝经济开发区500强。这时候,XHD夫妇也退居了二线,并在风景秀美的诸暨市浬浦镇陶姚村买了个房子,开始安度晚年了。
    这样住了一段时间,徐总对当地的交通还是不太了解。有时很郁闷,想去一个地方又不知道应该乘什么公交车,在什么地方转车,在什么地方下车(其实徐总自己有车,却一定要与民同乐,这就是徐总的性格)。
    徐总经常会问蹩脚的英文问路:“Can you help me?”。看着他那迷茫而又无助的眼神,热心的你能帮帮他吗?
    请帮助他用最短的时间到达目的地(假设每一路公交车都只在起点站和终点站停,而且随时都会开)。
    Input
    输入数据有多组,每组的第一行是公交车的总数N(0<=N<=10000);
    第二行有徐总的所在地start,他的目的地end;
    接着有n行,每行有站名s,站名e,以及从s到e的时间整数t(0<t<100)(每个地名是一个长度不超过30的字符串)。
    note:一组数据中地名数不会超过150个。
    如果N==-1,表示输入结束。
    Output
    如果徐总能到达目的地,输出最短的时间;否则,输出“-1”。
    View Code

    样例:

    Sample Input
    6
    xiasha westlake
    xiasha station 60
    xiasha ShoppingCenterofHangZhou 30
    station westlake 20
    ShoppingCenterofHangZhou supermarket 10
    xiasha supermarket 50
    supermarket westlake 10
    -1
    
    Sample Output
    50
    
    
    Hint:
    The best route is:
    xiasha->ShoppingCenterofHangZhou->supermarket->westlake

    题意:问给定的起点到终点的最短时间。

    思路:dijkstra模板

    注意:坑比较多

    • 起点和终点可能是同一个点
    • 双向边且取最小值
    • 有map的应用,用于给定的起点和终点都是字符串,给定经过的点也是以字符串的形式存储
    sum=0;
    string st,en;
    cin>>st>>en;
    mp[st]=++sum;
    mp[en]=++sum;
    for(int i=1; i<=n; i++)
    {
        string ss,ee;
        int t;
        cin>>ss>>ee>>t;
        if(!mp[ss])
            mp[ss]=++sum;
        if(!mp[ee])
            mp[ee]=++sum;
        if(e[mp[ss]][mp[ee]]>t||e[mp[ee]][mp[ss]]>t)
            e[mp[ss]][mp[ee]]=e[mp[ee]][mp[ss]]=t;
    }

    顺带回顾一下dijkstra

     1 void dijkstra()
     2 {
     3     for(int i=1;i<=sum;i++)
     4     {
     5         dist[i]=e[1][i];
     6         book[i]=0;
     7     }
     8     book[1]=1,dist[1]=0;
     9     int u;
    10     for(int i=2;i<=sum;i++)
    11     {
    12         int minn=inf;
    13         for(int j=1;j<=sum;j++)
    14         {
    15             if(book[j]==0&&minn>dist[j])
    16             {
    17                 u=j;
    18                 minn=dist[j];
    19             }
    20         }
    21         if(minn==inf)
    22             break;
    23         book[u]=1;
    24         for(int j=1;j<=sum;j++)
    25         {
    26             if(book[j]==0&&dist[u][j]<inf)
    27             {
    28                 if(dist[u]+e[u][j]<dist[j])
    29                     dist[j]=dist[u]+e[u][j];
    30             }
    31         }
    32     }
    33 
    34 }
    View Code

    AC代码如下:

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<queue>
      6 #include<map>
      7 #include<cmath>
      8 using namespace std;
      9 #define inf 0x3f3f3f3f
     10 const int N=1e4+20;
     11 
     12 int e[N][N],dist[N];
     13 int sum;
     14 bool book[N];
     15 map<string,int>mp;
     16 
     17 void init()
     18 {
     19     for(int i=1;i<=150;i++)
     20     {
     21         for(int j=1;j<=150;j++)
     22         {
     23             if(i==j)
     24                 e[i][j]=0;
     25             else
     26                 e[i][j]=inf;
     27         }
     28     }
     29 }
     30 
     31 void dijkstra()
     32 {
     33     for(int i=1;i<=sum;i++)
     34     {
     35         dist[i]=e[1][i];
     36         book[i]=0;
     37     }
     38     book[1]=1,dist[1]=0;
     39     int u;
     40     for(int i=2;i<=sum;i++)
     41     {
     42         int minn=inf;
     43         for(int j=1;j<=sum;j++)
     44         {
     45             if(book[j]==0&&minn>dist[j])
     46             {
     47                 u=j;
     48                 minn=dist[j];
     49             }
     50         }
     51         if(minn==inf)
     52             break;
     53         book[u]=1;
     54         for(int j=1;j<=sum;j++)
     55         {
     56             if(book[j]==0)
     57             {
     58                 dist[j]=min(dist[j],dist[u]+e[u][j]);
     59             }
     60         }
     61     }
     62 
     63 }
     64 
     65 int main()
     66 {
     67     ios::sync_with_stdio(false);
     68     int n;
     69     while(cin>>n)
     70     {
     71         if(n==-1)
     72             break;
     73         mp.clear();
     74         init();
     75         sum=0;
     76         string st,en;
     77         cin>>st>>en;
     78         mp[st]=++sum;
     79         mp[en]=++sum;
     80         for(int i=1;i<=n;i++)
     81         {
     82             string ss,ee;
     83             int t;
     84             cin>>ss>>ee>>t;
     85             if(!mp[ss])
     86                 mp[ss]=++sum;
     87             if(!mp[ee])
     88                 mp[ee]=++sum;
     89             if(e[mp[ss]][mp[ee]]>t||e[mp[ee]][mp[ss]]>t)
     90                 e[mp[ss]][mp[ee]]=e[mp[ee]][mp[ss]]=t;
     91         }
     92         //cout<<"---"<<sum<<endl;
     93         dijkstra();
     94         if(st==en)
     95         {
     96             cout<<0<<endl;
     97             continue;
     98         }
     99         //int w=e[1][2];
    100         int w=dist[2];
    101         if(w!=inf)
    102             cout<<w<<endl;
    103         else
    104             cout<<"-1"<<endl;
    105     }
    106     return 0;
    107 }
    View Code

          

    HDU6714-最短路2-Floyd

    • 法一:一种是用dijkstra写的,但是我没看懂。。。

                         参考博客:https://blog.csdn.net/birdmanqin/article/details/100068433

                                           https://www.cnblogs.com/iat14/p/11408298.html

    • 法二:一种用floyd写的(以下思路和代码是用floyd写的)

    题面:

    小 A 是社团里的工具人,有一天他的朋友给了他一个 n 个点,m 条边的正权连通无向图,要他计算所有点两两之间的最短路。
    
    作为一个工具人,小 A 熟练掌握着 floyd 算法,设 w[i][j] 为原图中 (i,j) 之间的权值最小的边的权值,若没有边则 w[i][j]=无穷大。特别地,若 i=j,则 w[i][j]=0。
    
    Floyd 的 C++ 实现如下:
    
    ```c++
    for(int k=1;k<=p;k++)
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
      w[i][j]=min(w[i][j],w[i][k]+w[k][j]);
    ```
    
    当 p=n 时,该代码就是我们所熟知的 floyd,然而小 A 为了让代码跑的更快点,所以想减少 p 的值。
    
    令 Di,j 为最小的非负整数 x,满足当 p=x 时,点 i 与点 j 之间的最短路被正确计算了。
    
    现在你需要求 ∑ni=1∑nj=1Di,j,虽然答案不会很大,但为了显得本题像个计数题,你还是需要将答案对 998244353 取模后输出。
    Input
    第一行一个正整数 T(T≤30) 表示数据组数
    
    对于每组数据:
    
    第一行两个正整数 n,m(1≤n≤1000,m≤2000),表示点数和边数。
    
    保证最多只有 5 组数据满足 max(n,m)>200
    
    接下来 m 行,每行三个正整数 u,v,w 描述一条边权为 w 的边 (u,v),其中 1≤w≤109
    Output
    输出 T 行,第 i 行一个非负整数表示第 i 组数据的答案
    
    Sample Input
    1
    4 4
    1 2 1
    2 3 1
    3 4 1
    4 1 1
    
    Sample Output
    6
    View Code

    题意:求所有顶点N中任意两点最短路中松弛点中最小值的和

    注意:

    • 用floyd很容易超时,这个地方处理很好。但是得放在第二层循环下,放在第三层会超时;
    if(e[i][k]>inff)
        continue;
    • 虽然每条边给的范围是109,但是由于floyd中会进行边的松弛,也就是会进行相加,所以需要开数组为ll;
    • 因为大部分数据开的为ll,所以在对于边的处理应该初始化为ll型的无穷大,也就是0x3f3f3f3f3f3f3f3f(8个3f),约19位;
    • 在处理数据的时候,第三层for循环到 j<i 即可,之后的结果*2,因为是双向边,所以后面的和前面一样也就无需重复处理了。

    代码如下:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<vector>
     7 #include<map>
     8 #include<cmath>
     9 using namespace std;
    10 #define inf 0x3f3f3f3f
    11 #define inff 0x3f3f3f3f3f3f3f3f
    12 const int N=1010;
    13 #define mod 998244353
    14 typedef long long ll;
    15 
    16 ll e[N][N],dist[N],a[N][N];
    17 int n,m;
    18 bool book[N];
    19 map<string,int>mp;
    20 
    21 void init()
    22 {
    23     for(int i=1;i<=n;i++)
    24     {
    25         for(int j=1;j<=n;j++)
    26         {
    27             if(i==j)
    28                 e[i][j]=0;
    29             else
    30                 e[i][j]=inff;
    31         }
    32     }
    33 }
    34 
    35 int main()
    36 {
    37     ios::sync_with_stdio(false);
    38     int t;
    39     cin>>t;
    40     while(t--)
    41     {
    42         cin>>n>>m;
    43         memset(a,0,sizeof(a));
    44         init();
    45         for(int i=1;i<=m;i++)
    46         {
    47             ll u,v,w;
    48             cin>>u>>v>>w;
    49             e[u][v]=e[v][u]=min(e[u][v],w);
    50         }
    51         ll ans=0;
    52         for(int k=1;k<=n;k++)
    53         {
    54             for(int i=1;i<=n;i++)
    55             {
    56                 if(e[i][k]>inff)
    57                         continue;
    58                 for(int j=1;j<i;j++)
    59                 {
    60                     if(e[i][j]>e[i][k]+e[k][j])
    61                     {
    62                         ans+=k;
    63                         ans-=a[i][j];
    64                         a[i][j]=a[j][i]=k;
    65                         e[i][j]=e[j][i]=e[i][k]+e[k][j];
    66                     }
    67                 }
    68             }
    69         }
    70         //i:4 j:2 k:1
    71         //i:3 j:1 k:2
    72         ll w=ans*2%mod;
    73         cout<<w<<endl;
    74     }
    75     return 0;
    76 }

    小知识点回顾:

    • 0x3f3f3f3f3f3f3f3f 代表针对longlong表示的无穷大,约19位
    • dijkstra:时间复杂度O(n2),一般求单源最短路

                             针对无负权边的图,有向无向都可以

                             存储结构上比较占空间,因为用的是邻接矩阵。

    • floyd:适用于N比较小的情况。

                          注意模板上k是写在最外层循环。

    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                e[i][j]=min(e[i][j],e[i][k]+e[k][j]);
            }
        }
    }
    • SPFA:不能处理负权回路;
    • 最短路在处理初始边的时候记得判断是否是双向边,是否需要取最小值;
    • 问起点到终点距离问题的时候,有时需要考虑一下起点是不是就是终点;
    • 记得对边进行初始化

     TO DO LIST

    • w 50+
    • 复习了最短路floyd/dijkstra

     待解决问题:

    • 为什么floyd的含k循环写在最外层? --> 枚举的松弛点
    • HDU6714 代码理解的不是很透彻,不确定自己理解的是否正确,需要推理出结果。???
  • 相关阅读:
    mysql命令集锦
    linux 删除文件名带括号的文件
    linux下的cron定时任务
    struts2文件下载的实现
    贴一贴自己写的文件监控代码python
    Service Unavailable on IIS6 Win2003 x64
    'style.cssText' is null or not an object
    "the current fsmo could not be contacted" when change rid role
    远程激活程序
    新浪图片病毒
  • 原文地址:https://www.cnblogs.com/OFSHK/p/12219824.html
Copyright © 2011-2022 走看看