图之四(最短路径)

来源:互联网 发布:阴线买入公式源码 编辑:程序博客网 时间:2024/05/01 23:19

1.        最短路径

1.1.       最短路径:

是带权有向图中,一个顶点u到另一顶点v之间权值最小的路径,最短路径可能不止一条。

最短路径不能含有负权回路,否则在负权回路上循环则可以达到负无穷大;也不能有正权回路,否则从路径上去掉回路后,可以产生有向图源点和终点、权值更小的路径。

因此最多有0权回路,而这时一定还有另外一条无回路的最短路径。因此可以将路径上的的0权回路都去掉。因此可以假定最短路径是无回路的。

1.2.       最短路径问题

²  单源点最短路径(求已知顶点到其余所有顶点的最短路径)

²  单终点最短路径(求图中任何顶点到特定顶点的最短路径;将边反向,转换为单源点问题)

²  单对顶点最短路径(已知顶点,已知终点的最短路径;在求单源的时候判断终点是否为所求终点即可)

²  每对顶点之间最短路径。

因此前三类可以归为一类;最后一类当然可以用单源点的方法对每个顶点循环一次,但这样复杂度太高,有更好的算法。

1.3.       最短路径的最优子结构

最短路径包含路径上任何两点之间的最短路径。

如果包含负权边,但无负权回路。则最短路径仍然成立,否则如果含有负权回路,则可以绕回路,权值可以为负的无穷大。

迪杰斯特拉(Dijkstra)算法只处理正权的图。

贝尔曼--福特(Bellman--Ford)算法可以处理负权边的情况,如果没有负权回路则计算返回成功,并处理结果;如果有负权回路,则返回失败。

1.4.       松弛技术

对每个顶点v,都设置一个属性d,代表当前从s到v的最短路径上权值的上界。称为最短路径估计。并设置一个属性p,代表最短路径树上v的父节点。

初始化时将所有顶点的d设置为无穷大,p设置为NIL。

松弛是对边(u,v)进行松弛,边为u到v的边。如果dv>du+w(u,v),即v的d值比u的d与边(u,v)的权大,则表示v有新的权值更小的路径,因此修改d域和p域。

不同算法的不同之处在于对边进行松弛的次数以及顺序。迪杰斯特拉算法对边只做一次松弛。贝尔曼---福特算法则会对边进行多次松弛。

“松弛”的概念主要是表示对边的d值进行减少。

2.        单源点最短路径

2.1.       Dijkstra迪杰斯特拉算法

条件:该算法主要解决带权有向图上的单源点路径算法,且权值非负。

算法思想:(和最小生成树的Prim算法类似,与广度优先算法也有相似地方)设置一个顶点集合S,源点s到S中元素的最短距离为已经确定。初始化时,只有源点s的d值为0,其余为无穷大。另外维护一个优先队列Q(以d域作为键),初始化时包含所有顶点。该队列为未确定最短距离的顶点集合。操作循环的取出最小元素u(也即会删除该元素),取出后u加入到S集合,并对u的所有邻接边进行“松弛”(隐含了需要调整优先队列,因为会修改d域,但并没有确定相应的邻接点v的d域,而只是将d域进行了松弛,这时候v还在Q中,并不在S集合中)。

算法持续进行,直到Q为空为止。

算法只适用于非负权值的原因在于:每次松弛时的点都为最短距离的点,并更新与其其相邻的点的d域,当权值为非负时,不会有一个距离更近的点没有被扩展。也即扩展的时候S中的集合的元素其d域是不会再减少的,因此算法能正确运行。如果扩展的时候有负权边,则会产生更小的权值,S中的集合的最短路径将不再成立。

特别情况,如果只有从s出发的边有可能为负权,其他任何顶点出发的边都不会有负权,且无负权回路,则迪杰斯特拉算法仍然有效。

2.2.       广度优先搜索可以看作权值全为1的最短路径问题,这时候的复杂度比其他的都小。直接用广度优先搜索即可完成。

2.3.       Bellman---Ford算法

条件:可以有负权边,只要没有负权回路即可正确解决。即便有负权回路也可也调整解决。

算法结束时,如果有负权回路则返回false;否则返回true,并计算出结果。

思想:对所有的边进行V-1趟松弛操作,每一趟都循环对所有边松弛一次,每一趟对边的松弛顺序还可以不同。最后再检查每一条边(u,v)。如果dv>du+w(u,v),即v的边还没有最优松弛,则有负权回路。否则没有,且dv即为最短路径的值。

2.4.       有向无回路图(DAG)单源点最短路径(以及关键路径)

特点:DAG图也即拓扑有序图,因此不存在回路,因此可以有负权边。

思想:算法先对DAG进行拓扑排序,再初始化d域和p域,以及源点的d域和p域。再对顶点按照拓扑排序的方式,对每个顶点的出边进行松弛。松弛完后即得结果。

关键路径求解:方法一是在以上算法中将权值取反(正权变负,负权变正),并运用上述算法;方法二是不修改权,且仍然使用上述算法,但在初始化时,边的d域改为负无穷,且对边松弛的时候,将大于变为小于比较。

3.        每对顶点之间的最短路径问题

3.1.       问题分类

²  如果是无权边,也即权值都相等。则可也用广度优先的方式,对每个顶点作为源点运算一次。

²  非负权边,直接运用迪杰斯特拉以每个顶点运算一次。

²  有负权边,但无负权回路,直接运用贝尔曼---福特算法以每个顶点运算一次。

以上解法都可以,但后两者除了局限外,复杂度也相应较高。因此引进一个更高效的算法。

3.2.       动态规划法(应用矩阵乘法)

算法思想:假设i到j的最多包含m条边的最短路径(与最短路径区别),则对j的前一个节点k(对每一条含义m条边的最短路径),有i,j最短路径为i,k最短路径加上w(k,j)。对m可以作递归,从m为0,直到n-1(因为n个顶点,最长的简单路径为n-1条边)。边的权值矩阵为m=1的情况。最后的最短路径矩阵为m=n-1的值。

由于权由邻接矩阵表示,因此递归求解的时候可以使用矩阵乘法的性质减少计算。

3.3.       动态规划(Floyd—Warshall,弗洛伊德算法)

算法思想:不是考虑“m条边”。而是考虑最短路径的中间点(路径上除了起点和终点的其他顶点)。并考虑中间点的下标的与{1,2,…k-1}的关系。如果中间点经过k,则最(i,j)短路径可以分解为(i,k),(k,j);如果中间点不经过k,则最短路径中间点只与{1,2…k-1}相关。(k为中间路径上的顶点下标最大的下标值)从而最短路径d(I,j)(k)为d(I,j)(k-1)与d(I,k)(k-1)+d(k,j)(k-1)中小的一个。

三重循环中对d(I,j)(k)进行松弛。

闭包问题

3.4.       稀疏图上的Johnson算法

思想:如果权值非负,则用迪杰斯特拉算法。否则对边的权值进行调整。

使用顶点的任何一个实值函数h:V->R作为辅助。

新的权值为:w~(u,v)=w(u,v)+h(u)-h(v)。则这两者有相同的最短路径,而且如果也同时有负权回路。