最短路问题(——模板习题和总结)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短路问题(——模板习题和总结)相关的知识,希望对你有一定的参考价值。

  最短路问题分为单源最短路问题和多源最短路问题,给出顶点数和边数,以及边的情况(包括起点和终点及权值),让我们计算从某个顶点到某个顶点的最短路径。

  先总结一下只有五行的Floyd算法,一句话概括就是:从i号顶点到j号顶点只经过前k号点的最短路程。

  模板题:http://www.cnblogs.com/wenzhixin/p/7327981.html

  AC代码:

  技术分享
 1 #include<stdio.h>
 2 int main()
 3 {
 4     int n,m,e[210][210],inf=99999999,t1,t2,t3,s,t,i,j,k;
 5     while(scanf("%d%d",&n,&m) != EOF)
 6     {
 7         for(i=0;i<n;i++)
 8         {
 9             for(j=0;j<n;j++)
10             {
11                 if(i==j)
12                 e[i][j]=0;
13                 else
14                 e[i][j]=inf;
15             }
16         }
17         for(i=1;i<=m;i++)
18         {
19             scanf("%d%d%d",&t1,&t2,&t3);
20             if(e[t1][t2] > t3)//道路可能存在重复,去最小值即可 
21             e[t1][t2]=e[t2][t1]=t3;
22         }
23         scanf("%d%d",&s,&t);
24         
25         for(k=0;k<n;k++)
26             for(i=0;i<n;i++)
27                 for(j=0;j<n;j++)
28                 if(e[i][j] > e[i][k]+e[k][j])
29                 e[i][j]=e[i][k]+e[k][j];
30         if(e[s][t]==inf)
31         printf("-1\\n");
32         else
33         printf("%d\\n",e[s][t]);
34     }
35     return 0;
36 }
View Code

  该算法的优势在于可以计算顶点数不太多的图的任意两点的最短路径,很容易实现求解多源最短路径。

  缺点在于不能计算顶点数太多的图的最短路径,一是二维数组开不了那么大,二是该算法时间复杂度太高,达到O(n*n*n),很容易超时(超过1000个顶点就不能使用)。

  另外该算法可以解决带负权边的图,并且均摊到每一对点上,但是不能解决带有负权回路的图(其实如果一个图中存在负权回路,那么该图不存在最短路径)。

  接下来,再总结一下求解单源最短路径常用的Dijkstra算法。

  基本步骤:1. 将所有的顶点分为两个集合,已知最短路径的顶点集合P和未知最短路径的顶点集合Q。起初,已知最短路径的顶点集合P中只有一个源点这一个顶点。我们还需要有一个数组来记录哪些顶点在集合P中,哪些在集合Q中。比如用book数组来标记,当book[i]=1;表示i号顶点在集合P中,当book[i]=0;表示i号顶点在集合Q中。

       2. 设置源点s到自己的最短路径为0即dis[s]=0;,如果存在有源点能够直接到达的顶点i,则将dis[i]赋值为e[s][i];如果不存在该源点直接到达的顶点i,则将

dis[i]赋值正无穷大。

       3. 在集合Q的所有顶点中选择一个离源点最近的顶点u加入到集合P。并考察所有以u为起点的边,对每一条边进行松弛操作。

       4. 重复第3步,如果集合为空,算法结束。

  模板习题:http://www.cnblogs.com/wenzhixin/p/7387613.html

  AC代码:

  技术分享
 1 #include<stdio.h>
 2 #include<string.h>
 3 int e[1010][1010],dis[1010],bk[1010];
 4 int main()
 5 {
 6     int i,j,min,t,t1,t2,t3,n,u,v;
 7     int inf=99999999;
 8     while(scanf("%d%d",&t,&n)!=EOF)
 9     {
10         for(i=1;i<=n;i++)
11         {
12             for(j=1;j<=n;j++)
13             {
14                 if(i==j)
15                 e[i][j]=0;
16                 else
17                 e[i][j]=inf;
18             }
19         }
20         for(i=1;i<=t;i++)
21         {
22             scanf("%d%d%d",&t1,&t2,&t3);
23             if(e[t1][t2]>t3)
24             {
25                 e[t1][t2]=t3;
26                 e[t2][t1]=t3;
27             }
28         }
29         for(i=1;i<=n;i++)
30             dis[i]=e[1][i];
31         memset(bk,0,sizeof(bk));
32         bk[1]=1;
33         for(i=1;i<=n-1;i++)
34         {
35             min=inf;
36             for(j=1;j<=n;j++)
37             {
38                 if(bk[j]==0&&dis[j]<min)
39                 {
40                     min=dis[j];
41                     u=j;
42                 }
43             }
44             bk[u]=1;
45             for(v=1;v<=n;v++)
46             {
47                 if(e[u][v]<inf && dis[v]>dis[u]+e[u][v])
48                         dis[v]=dis[u]+e[u][v];
49             }
50         }
51         printf("%d\\n",dis[n]);
52     }
53     return 0;
54 }
View Code

  上述算法的时间复杂度为O(n*n),还是很高的,可以使用邻接表存储图,再使用堆优化(原谅笔者技术有限,日后补充)。但是竞赛题大多是对Dijkstra算法的

变形应用,例如求解最短路径的最大权值,最长路径的最小权值。

  最长路径的最小权值:http://www.cnblogs.com/wenzhixin/p/7336948.html

  最长路径的最小权值:http://www.cnblogs.com/wenzhixin/p/7412176.html

  

  


以上是关于最短路问题(——模板习题和总结)的主要内容,如果未能解决你的问题,请参考以下文章

最短路问题常用算法总结和模板

LGOJ5651基础最短路练习题

最短路径模板总结

二分图匹配问题(——模板习题与总结)

《算法竞赛进阶指南》图论习题

习题:最短路计数(SPFA最短路计数)