您的位置:首页 > 其它

算法导论 - 第24章 单源最短路径

2011-12-14 18:48 309 查看
单源最短路径的算法有两种:Bellman-Ford算法和Dijkstra算法。求最短路径,如果最短路径上存在weight小于0的cycle,则不存在最短路径。因为只要在这个cycle上多循环几次,该路径的weight就会降低。因此求最短路径的weight时,应该判断最短路径上是否存在weight小于0的cycle,如果存在weight小于0的cycle,则无法对该图求最短路径,因为没有意义。

假设源点为s。在每个顶点中保存一个变量用来保存到源点s的最短路径的weight。为方便,用d(u)来表示顶点u到源点s的最短路径的weight。初始值都设为正无穷大,源点s的d值设为0。Bellman-Ford算法和Dijkstra算法的过程就是不断更新每个顶点的d值,直到最小。w(u,v)表示边(u,v)的weight。

函数Relaxation(int u,int v)用来更新顶点的d值。

void Relaxation(int u,int v)
{
if(d(v)>d(u)+w(u,v))
{
d(v) = d(u)+w(u,v);
}
}


Bellman-Ford算法可以判断是否存在weight小于0的cycle。而Dijkstra只能在所有的edge的weight都大于等于0的网上运行。

1 Bellman-Ford算法

假设路径(s,p1)(p1,p2)(p2,p3)(p3,p4)(p4,p5)...(pn-1,pn)是顶点s到pn的最短路径。显然,该路径也必然是到中间顶点的最短路径。即(s,p1)(p1,p2)(p2,p3)必然是s到p3的最短路径。因此,假如我们按这个edges的顺序计算p1,p2,p3,p4...pn的d值,只需计算一次就可以得到源点到pn的最短路径的weight。

但我们事先不可能知道到每个顶点的最短路径。所以不可能正好按照最短路径的顺序来计算每个顶点的最短路径的weight值。但我们要注意到,如果我们打乱顺序来更新px的d值,p1的d值肯定能被正确得计算。如果我们再来一次随机更新所有顶点的d值,p2顶点的d值也能被正确地计算。如此,我们重复n遍,就能把该路径上所有顶点的d值都计算出来。

考虑到源点s到任何顶点的最短路径都不会超过n-1,我们只需要进行n-1次遍历就可以。

2 Dijkstra算法

Dijkstra算法只需将所有的边遍历一次就能算的所有顶点到源点的最短路径的weight。Dijkstra法将所有的顶点分为两个集合A和B:A是已经得到正确d值的顶点,B是还没算的d值得顶点。刚开始时,A只包括顶点s。B包括所有其他的顶点。对所有以s为尾的边调用Relaxation,更新与之相连的顶点的d值。然后从B中所有的顶点中选出最小的d值的顶点v,加入到A中,并对所有以v为尾的边调用Relaxation。如此循环,直到所有的顶点都加入到A中。

该算法的关键是如何快速从B中选出最小d值的顶点。由于只需要选出最小d值的顶点,因此集合B用最小堆来实现最合适。

它的计算步骤为:

1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: