zoukankan      html  css  js  c++  java
  • HDU 1874 最直接的最短路径问题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1874

    Problem Description
    某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。
    现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。
     
    Input
    本题目包含多组数据,请处理到文件结束。 每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。 接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。 再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。
     
    Output
    对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.
     
    在这道题中因为数据量不大,所以用四种最短路径的方法都可以对它进行求解,也用这道题来令自己熟悉一下四种最短路径的算法:
     
    Dijkstra:
     1 #include <cstdio>
     2 #include <algorithm>
     3 #include<queue>
     4 #include<cstring>
     5 using namespace std;
     6 typedef pair<int,int> pii;
     7 #define N 205
     8 #define M 1005
     9 #define MAXN 0x3f3f3f3f
    10 int y[M],d[M],next[M];
    11 int first[N],dp[N];
    12 int k;
    13 
    14 //写完函数后这两句话老是忘记写,所以还是这样一开始就写在一个函数里这样自己就不会忘了
    15 void init()
    16 {
    17     k=0;
    18     memset(first,-1,sizeof(first));
    19 }
    20 void add(int a,int b,int c)
    21 {
    22     y[k]=b,d[k]=c,next[k]=first[a];
    23     first[a]=k;
    24     k++;
    25 }
    26 
    27 void dijkstra(int src)
    28 {
    29     priority_queue<pii,vector<pii>,greater<pii> > q;
    30     memset(dp,0x3f,sizeof(dp));
    31     dp[src]=0,q.push(make_pair(0,src));
    32     while(!q.empty()){
    33         while(!q.empty()&&dp[q.top().second]<q.top().first) q.pop();
    34         if(q.empty()) break;
    35         int u=q.top().second;
    36         q.pop();
    37         for(int i=first[u];i!=-1;i=next[i]){
    38             if(dp[y[i]]>dp[u]+d[i]){
    39                 dp[y[i]]=dp[u]+d[i];
    40                 q.push(make_pair(dp[y[i]],y[i]));
    41             }
    42         }
    43     }
    44 }
    45 
    46 int main()
    47 {
    48     int n,m,a,b,c,s,t;
    49     while(scanf("%d%d",&n,&m)!=EOF){
    50         init();
    51         for(int i=0;i<m;i++){
    52             scanf("%d%d%d",&a,&b,&c);
    53             add(a,b,c);
    54             add(b,a,c);
    55         }
    56         scanf("%d%d",&s,&t);
    57         dijkstra(s);
    58         if(dp[t]<MAXN) printf("%d
    ",dp[t]);
    59         else printf("%d
    ",-1);
    60     }
    61 
    62     return 0;
    63 }
    View Code
    SPFA:
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <queue>
     5 using namespace std;
     6 #define MAXN 20010
     7 #define N 205
     8 int v[MAXN],d[MAXN],next[MAXN],first[N],visit[N],dp[N];
     9 int k;//k表示路的条数
    10 
    11 void add(int x,int y,int a)//这里添加的是无向图的边,所以进行两次
    12 {
    13     v[k]=y;
    14     next[k]=first[x];
    15     d[k]=a;
    16     first[x]=k;
    17     k++;
    18     v[k]=x;
    19     next[k]=first[y];
    20     d[k]=a;
    21     first[y]=k;
    22     k++;
    23 }
    24 
    25 int spfa(int a,int b)
    26 {
    27     memset(dp,0x3f,sizeof(dp));
    28     //memset(visit,0,sizeof(visit));//这一段是没有必要的,每次spfa做完,他都会最后变为0
    29     queue<int> q;
    30     dp[a]=0,visit[a]=1;
    31     q.push(a);
    32     while(!q.empty()){
    33         int c=q.front();
    34         q.pop();
    35         visit[c]=0;
    36         for(int i=first[c];i!=-1;i=next[i]){
    37             if(dp[v[i]]>dp[c]+d[i]){
    38                 dp[v[i]]=dp[c]+d[i];
    39                 if(!visit[v[i]]) q.push(v[i]),visit[v[i]]=1;
    40             }
    41         }
    42     }
    43     if(dp[b]<0x3f3f3f3f) return dp[b];
    44     else return -1;
    45 }
    46 
    47 int main()
    48 {
    49     int n,m,start,End,x,y,a;
    50     while(scanf("%d%d",&n,&m)!=EOF){
    51         k=0;
    52         memset(next,-1,sizeof(next));
    53         memset(first,-1,sizeof(first));
    54         for(int i=0;i<m;i++){
    55             scanf("%d%d%d",&x,&y,&a);
    56             add(x,y,a);
    57         }
    58         scanf("%d%d",&start,&End);
    59         printf("%d
    ",spfa(start,End));
    60     }
    61     return 0;
    62 }
    View Code


    Floyd:

    在使用Floyd时应该把矩阵每个点一开始做好初始化,主对角线上均为0;

    其他定位一个最大值。

    PS:这道题比较坑的地方是两地间可以有多条路,我们要判断是否为较小的路放入矩阵中

    floyd是基于建立在2维矩阵中的,每次更新出一个到达 i 的最短路径,都要遍历一次矩阵,把所有其他节点到 i 点最小值不断更新出来,因为这道题城镇数目比较少,可以采取这种

    复杂度为O(n^3)的方法,但是通过这个方法我们可以确定任意一点到其他点的最短路径(自我感觉类似于打表法,有木有?!),不像SPFA做一次只能找到你所需的最短路径

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 #define N 205
     7 #define MAXN 0x3f3f3f3f
     8 int mat[N][N];
     9 
    10 void Floyd(int n)//为n*n的矩阵
    11 {
    12     for(int i=0;i<n;i++){
    13         for(int j=0;j<n;j++){
    14             for(int k=0;k<n;k++){
    15                 if(mat[j][k]>mat[j][i]+mat[k][i])
    16                     mat[j][k]=mat[j][i]+mat[k][i];//i只是用来计更新次数的,实际上每更新一次,都要将整个矩阵的所有点都遍历一遍
    17                 }                                 //所以是mat[j][k];
    18         }
    19     }
    20 }
    21 int main()
    22 {
    23     int n,m,start,End,x,y,a;
    24     while(scanf("%d%d",&n,&m)!=EOF){
    25         memset(mat,0x3f,sizeof(mat));
    26         for(int i=0;i<n;i++) mat[i][i]=0;
    27         for(int i=0;i<m;i++){
    28             scanf("%d%d%d",&x,&y,&a);
    29             a=min(a,mat[x][y]);
    30             mat[x][y]=a,mat[y][x]=a;//在这里要判断一下,因为两地之间可以有多条路,我们需要判断它到底是否为我们要的最短路
    31         }
    32         scanf("%d%d",&start,&End);
    33         Floyd(n);
    34         if(mat[start][End]<MAXN) printf("%d
    ",mat[start][End]);
    35         else printf("-1
    ");
    36     }
    37     return 0;
    38 }
    View Code


    BellMan-ford:

    在写BellMan时,没必要写first[]数组了

    它执行一次只能找到固定对应的a到b的最短距离,在这一点上是远远不如Floyd的,而且复杂度为O(n*k),在数据量特别大时是不适用的

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 #define N 205
     7 #define M 20005
     8 #define MAXN 0x3f3f3f3f
     9 int u[M],v[M],d[M],k;
    10 int dp[N];
    11 void add(int x,int y,int a)
    12 {
    13     u[k]=x,v[k]=y,d[k]=a;
    14     k++;
    15 }
    16 void BellMan(int n,int src)
    17 {
    18     memset(dp,0x3f,sizeof(dp));
    19     dp[src]=0;
    20     for(int i=0;i<n;i++)
    21     {
    22         for(int j=0;j<k;j++)
    23             if(dp[v[j]]>dp[u[j]]+d[j])
    24                 dp[v[j]]=dp[u[j]]+d[j];
    25     }
    26 }
    27 int main()
    28 {
    29     int n,m,start,End,x,y,a;
    30     while(scanf("%d%d",&n,&m)!=EOF){
    31         k=0;
    32         for(int i=0;i<m;i++){
    33             scanf("%d%d%d",&x,&y,&a);
    34             add(x,y,a);
    35             add(y,x,a);
    36         }
    37         scanf("%d%d",&start,&End);
    38         BellMan(n,start);
    39         if(dp[End]<MAXN) printf("%d
    ",dp[End]);
    40         else printf("-1
    ");
    41     }
    42     return 0;
    43 }
    View Code
  • 相关阅读:
    常见数据结构的Java实现
    ASP.NET WEB API的服务托管(Self-HOST)
    Twitter Bootstrap3小结
    RESTful API后台系统架构设计(Java)
    同步函数的异步化
    C#并行库(TaskParallelLibrary)用法小结
    RestSharp用法小结
    如何选择JAVA培训机构,兼议什么样的人适合培训机构
    从零开始理解JAVA事件处理机制(3)
    简单实用UML关系图解
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/3873601.html
Copyright © 2011-2022 走看看