zoukankan      html  css  js  c++  java
  • 最短路相关

    求一个图的最短路径。

    一、多源最短路

    1.Floyed-Wallsahll算法

    借用动态规划的思想,是枚举中转点,其中核心语句的原型是mp[i][k][k-1]+mp[k][j][k-1]<=mp[i][j][k],只不过因为最后的k,k-1没什么用,就压缩成了二维。

    代码:

     1 for(int k=1;k<=n;k++)//k循环一定要在外面 
     2     {
     3         for(int i=1;i<=n;i++)
     4         {
     5             for(int j=1;j<=n;j++)
     6             {
     7                 if(mp[i][j]>mp[i][k]+mp[k][j])
     8                 {
     9                     mp[i][j]=mp[i][k]+mp[k][j];//核心算法语句 
    10                 }
    11             }
    12         }
    13     }

    借助Floyed算法,加入path[][]数组,可以进行路径的保存,最终实现路径输出。代码如下:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 const int maxn=1000; 
     5 const int inf=0x3f3f3f3f;
     6 int path[maxn][maxn];
     7 int mp[maxn][maxn];
     8 int n,m;
     9 void Floyed()//Floyed算法核心语句 
    10 {
    11     int i,j,k;
    12     for(i=1;i<=n;i++)
    13     {
    14         for(j=1;j<=n;j++)
    15         {
    16             if(mp[i][j]<inf&&i!=j)
    17             path[i][j]=j;//记录能到达的路径 
    18             else
    19             path[i][j]=-1;
    20         }
    21     }
    22     for(k=1;k<=n;k++)
    23     {
    24         for(i=1;i<=n;i++)
    25         {
    26             for(j=1;j<=n;j++)
    27             {
    28             if(mp[i][j]>mp[i][k]+mp[k][j])
    29             {
    30             mp[i][j]=mp[i][k]+mp[k][j];
    31             path[i][j]=path[i][k];//更新路径 
    32             }
    33         }
    34     }
    35 }
    36 }
    37 void Output(int start,int end)//最短路输出 
    38 {
    39     int next=start;
    40     printf("%d",start);
    41     while(next!=end)
    42     {
    43         printf("-->");
    44         printf("%d",path[next][end]);
    45         next=path[next][end];
    46     }
    47     cout<<endl;
    48 }
    49 int main()
    50 {
    51     cin>>n>>m;
    52     for(int i=1;i<=n;i++)
    53     {
    54         for(int j=1;j<=n;j++)
    55         {
    56             if(i==j)
    57             mp[i][j]=0;
    58             else
    59             mp[i][j]=inf;
    60         }
    61     }
    62     int a,b,c;
    63     for(int i=1;i<=m;i++)
    64     {
    65         scanf("%d%d%d",&a,&b,&c);
    66         mp[a][b]=c;
    67         mp[b][a]=c;
    68     }
    69     Floyed();
    70     int Qa,Qb;
    71     while(cin>>Qa>>Qb)
    72     {
    73     cout<<mp[Qa][Qb]<<endl;
    74     Output(Qa,Qb);
    75 }
    76     return 0;
    77 }
    View Code

    二、单源最短路

    1.Dijkstra算法

    借助贪心算法的思想。

    主要用来计算一个节点到其他所有点的最短路径。以起点为中心点向外拓展。

    该算法的要求:图中不存在负权边。

    其中典型的操作松弛。首先用dis[]数组记录源点到其他所有点的距离并标记正无穷,然后从源点开始,比如dis[3]表示1到3的距离,此时比较dis[3]和dis[2]+mp[2][3],即如果此时1到3的距离通过点2松弛如果更小,那么更新,其他依次操作,直到所有点都更新完成。

    代码:

     1     int book[50],min,u,v,i,j;
     2     for(i=1;i<=n;i++)//把距离改为源点到所有可直接连通点的距离 
     3     {
     4         dis[i]=map[1][i];
     5     }
     6     for(i=1;i<=n;i++)//标记 
     7     {
     8         book[i]=0;
     9     }
    10     book[1]=1;//1已经遍历过 
    11     for(i=1;i<=n-1;i++)//进行n-1次操作 
    12     {//操作是寻找距离1号最近的顶点 
    13         min=din;
    14         for(j=1;j<=n;j++)//寻找可以更新的点 
    15         {
    16             if(book[j]==0&&dis[j]<min)
    17             {
    18                 min=dis[j];
    19                 u=j;
    20             }
    21         }
    22         book[u]=1;
    23         for(v=1;v<=n;v++)
    24         {
    25             if(map[u][v]<din)
    26             {
    27                 if(dis[v]>dis[u]+map[u][v])
    28                 {
    29                     dis[v]=dis[u]+map[u][v];
    30                 }
    31             }
    32         }
    33     }

     2.Bellman_Ford算法

    采用“松弛”的策略,从原点到每个点的方案作对比,逐步更新,更新n(顶点)-1次后,一定全部更新完毕,再次判断是否可更新,如果还可更新,则一定存在负权回路。

    代码如下:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 const int inf=0x3f3f3f3f;
     5 const int maxn=1e5;
     6 struct Edge
     7 {
     8     int u,v,w;
     9 };
    10 Edge e[maxn];
    11 int dis[maxn],pre[maxn];
    12 int n,m,s;//n为点数,m为通路条数,s为源点 
    13 
    14 bool Bellman_Ford()
    15 {
    16     for(int i=1;i<=n;i++)//初始化源点到其他各个点的距离 
    17     {
    18         if(i==s)
    19         dis[i]=0;
    20         else
    21         dis[i]=inf;
    22     }
    23     for(int i=1;i<=n-1;i++)//核心代码,“松弛”操作 
    24     {
    25         for(int j=1;j<=m;j++)
    26         {
    27             if(dis[e[j].v]>dis[e[j].u]+e[j].w)
    28             {
    29             dis[e[j].v]=dis[e[j].u]+e[j].w;
    30             pre[e[j].v]=e[j].u;//前驱路线更新 
    31             }
    32         }
    33     }
    34     bool flag=true;//判断是否含有负权回路的标志 
    35     for(int i=1;i<=m;i++)
    36     {
    37         if(dis[e[i].v]>dis[e[i].u]+e[i].w)
    38         {
    39             flag=false;
    40             break;
    41         }
    42     }
    43     return flag;
    44 }
    45 void Output_path(int s)//路径输出的函数 
    46 {
    47     while(s!=pre[s])
    48     {
    49         printf("%d",s);
    50         printf("-->");
    51         s=pre[s];
    52     }
    53     if(s==pre[s])
    54     cout<<s<<endl;
    55 }
    56 int main()
    57 {
    58     cin>>n>>m;
    59     cin>>s;
    60     for(int i=1;i<=n;i++)
    61     {
    62         scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    63     }
    64     pre[s]=s;
    65     bool flag;
    66     flag=Bellman_Ford();
    67     if(flag)
    68     {
    69         for(int i=1;i<=n;i++)
    70         {
    71             printf("%d
    ",dis[i]);
    72             Output_path(i);
    73         }
    74     }
    75     else
    76     printf("图中含有负权回路。
    ");
    77     return 0;
    78 }
    View Code
  • 相关阅读:
    NET Core 2.2
    NET Core项目模板
    Eclipse同时显示多个控制台项目的输出
    Java中的序列化
    Java中的泛型
    Java中的集合
    Java中的数据结构
    Java中的包
    Java中的接口
    Java中的封装
  • 原文地址:https://www.cnblogs.com/theshorekind/p/13368030.html
Copyright © 2011-2022 走看看