序
![](https://img-blog.csdnimg.cn/20210317231748764.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1NTA1MzQx,size_16,color_FFFFFF,t_70)
路径松弛性质
在讨论最短路径算法前,先讨论一个重要性质
![](https://img-blog.csdnimg.cn/20210317232040142.png)
具体的说,如下图1,只要依次对V0->v1,v1->v2,v2->v3这三条边依次进行松弛操作,就能求出结点v0到结点v3的最短路径。
所以这里就有三个问题,一个是什么是松弛操作,一个是怎么依次对v0->v1,v1->v2,v2->v3进行松弛操作,第三个问题是路径松弛性质如何证明。
松弛操作
![](https://img-blog.csdnimg.cn/20210317234449382.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzE1NTA1MzQx,size_16,color_FFFFFF,t_70)
具体地说,就是对每个结点V维护一个属性d(这个属性也可以用数组存储,如d[0])和属性π。属性d表示的是起点V0到结点V的路径的距离;属性π表示的是,已找到路径中,V的前驱结点,通过这个π属性可以回溯出整条最短路径。
然后先进行初始化INITIALIZE-SINGLE-SOURCE操作,这会将每个结点的d设置为无穷大,π设置为NIL即无前驱,而v0.d会被设置为0。
假设此时对v0->v1这条边进行松弛操作(即执行 RELAX(v0,v1,w)),RELAX函数第一行的判断,带入值会得到 ,然后v1.d会被设置为2,π被设置为v0。
再依次对v1->v2,v2->v3进行松弛操作后的结果如下
当然,假如把图中唯一未标记的那个顶点标记为v4,然后对v0->v4,v4->v3进行松弛操作,v3.d依然为9。
Bellman-Ford算法
bellman-ford算法给出了第二个问题(怎么依次对v0->v1,v1->v2,v2->v3进行松弛操作)的一个回答,大概思想是这样的:先对全图的边进行一次松弛操作,(v0->v1毋庸置疑是图中的一条边,全图的边都已经将进行松弛操作了,v0->v1就一定也被进行了松弛操作);再对全图的边进行一次松弛操作,(毋庸置疑的,v1->v2肯定也被松弛了);再对全图的边进行一次松弛操作(这时候v2->v3也被松弛了)······
时间复杂度显然为O(VE)
这个角落太小,等看完DAG的最短路径再贴上证明(
DAG的单源最短路径
对于无圈有向图来说,结点S到结点V的最短路径中如果存在中间结点,那么S,V和这些中间结点在最短路径中的先后顺序和在拓扑排序中的先后顺序不变,即在最短路径和拓扑排序中,都是S排在前面,中间节点依次排在中间,V排在最后面。
如下图2,s->x->y->z是s到z的最短路径,而在拓扑排序中,他们的顺序也是s-x-y-z。
所以说,想要依次对无权有向图的S到V的最短路径上的边依次进行松弛操作,只要遍历这个图的拓扑排序S到V中间的结点(含S和V),每遍历到一个顶点时,将这个顶点所有的边进行松弛操作,这样就恰好依次对S到V最短路径上的边进行了松弛操作,也就能找到了最短路径。
算法复杂度显然为O(V+E)
特别的,也可类似地求出一条关键路径(最长路径)
路径松弛性质证明
要证明路径松弛性质,要先证明上届性质和收敛性质
然后就能证明路径松弛性质
Bellman-Ford算法证明
上述DAG最短路径算法的证明