最短路相关

求一个图的最短路径。

一、多源最短路

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\n",dis[i]);
72             Output_path(i);
73         }
74     }
75     else
76     printf("图中含有负权回路。\n");
77     return 0;
78 }
View Code

 

posted on 2020-09-09 09:52  轻描淡写ぃ  阅读(133)  评论(0编辑  收藏  举报

导航