原文链接 http://dongzi85.blog.163.com/blog/static/8079890520089288468222/
最短路径算法
分类:
- 无回路网络:拓扑排序法
- 无负权网络:Dijkstra算法,Bellman-Ford算法
- 带负权网络:Bellman-Ford算法
- 所有点对之间的最短路径:Floyd-Warshall算法
在图中存在负权的情况下,最短路径不一定存在。可以证明:
- [定理]:在无向连通图中,两点间的最短路径存在当且仅当不含负权圈(往死里转吧,无穷小)。
Bellman Ford算法(SSSP):
基本思想:如果两点间有最短路,那么每个顶点最多经过一次。如果一个顶点经过两次,那么必定走了一个圈,如果这是个正圈,显然是不合算的;如果是负圈,则根据上述定理,不存在最短路径。
初始化d[起点]=0,d[其他点]= 无穷
for k=1 to n-1 do
for 每条边 (u,v) do
if (d[u]<无穷) and (d[u]+w(u,v)<d[v])then d[v]=d[u]+w(u,v);
时间复杂度O(mn)。
Floyd-Warshall算法(ASSP):
求多源、无负权边的最短路。用矩阵记录图。时效性较差,时间复杂度O(V^3)。
Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理
有向图最短路径问题。
Floyd-Warshall算法的时间复杂度为O(N^3),空间复杂度为O(N^2)。
Floyd-Warshall的原理是动态规划:
考虑最短路的最优子结构性质。设d[i,j,k]是从节点i到节点j的最短路径,且只允许经过[1...k]中的节点,考察节点k,有两种情况:
- 经过k:则d[i,j,k]=d[i,k,k-1]+d[k,j,k-1]
- 不经过k:则d[i,j,k]=d[i,j,k-1]
for k=1 to n do
for i=1 to ndo
for j=1 to ndo
if (d[i,k]<无穷) and(d[k,j]<无穷)and d[i,k]+d[k,j]<d[i,j]then
d[i,j]=d[i,k]+d[k,j];
时间复杂度为O(n3).
最短路算法总结:
- 标号修正算法(Bellman-Ford):算法迭代式的,标号都是临时的,算法思想是不断逼近最优解,最后一步达到最优解。
- 标号设定算法(Dijkstra):算法执行过程就是不断把临时标号设定成为永久标号的过程。
- 标号设定算法时间复杂度低,但适用范围小,例如Dijkstr算法就不适用于含负权边的情况。标号修正算法适用范围相对较广,但时间复杂度较高。
附模板(原文链接 http://www.cnblogs.com/touchsunlight/archive/2010/08/09/1795816.html)
完全最短路径(Floyd算法):[复杂度:O(n^3)]
|
单源最短路径Dijkstra算法:
Bellman-Ford算法:
适用范围:
- 单源最短路径(从源点s到其它所有顶点v);
- 有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图);
- 边权可正可负(如有负权回路输出错误提示);
- 差分约束系统;
算法描述:
- 对每条边进行|V|-1次Relax操作;
- 如果存在(u,v)∈E使得dis[u]+w<dis[v],则存在负权回路;否则dis[v]即为s到v的最短距离,pre[v]为前驱。