标签:
上一周去了一趟说走就走的治疗之旅,所以算法课都没能上。:( 不过,人生有过这样一次,很足够。只要永远做自己认为对的事情就不会有跨不过去的坎。
跟上周一样,这一周的内容包含几个小部分,分别为最短路径动态规划、所有点对之间的最短路径和网络流。
第一部分:最短路径动态规划
对于一个有向图G=(V, E), 每一条边权重为cvw(权重可为负), 问题是找到从节点s到t的最短的路径。如果边的权重中有负值,则Dijkstra方法不适用。因此我们想到一个办法,给每一个权值加上一个正常数使得每一条边的权重都为非负,这个方法也不行。
这里定义一个负(成本)环。如下图所示,顾名思义,所有边的权值的和为负数。
如果一个从s到t的路径中包含一个负(成本)环,那s-t之间不存在最短路径,否则,存在一个最短路径。如下图。
下面用动态规划来解决最短路径的问题。
定义OPT(i, v) 表示使用最多i条边的最短的v到t的路径P。
1) P中使用最多i-1条边
OPT(i, v) = OPT(i - 1, v)
2) P使用第i条边
如果(v, w)是第一条边,那么OPT使用(v, w), 然后选择最佳的w-t路径使用最多i-1条边
通过之前的观察,可以得出,如果没有负环,那么OPT(n - 1, v)为最短的v-t路径的长度。
实现代码如下:
时间复杂度为O(mn), 空间复杂度为O(n^2).
下面提出一种改进。
保持一个矩阵M[v]为我们目前能够找到的最短的v-t路径。除非M[v]在前一个迭代中改变了,否则不需要检查(v, w)形成的边。这里有这样一个定理,在整个算法中,M[v]是v-t路径的长度,在i轮更新之后,M[v]不会大于使用不多于i条边的最短路径的长度。内存消耗为O(m+n),时间复杂度为O(mn)最坏情况,但是实际会更快。
Bellman-Ford实现算法如下:
使用以上算法可以证明,如果对于所有的v有OPT(n, v) = OPT(n - 1, v),那么就没有负环。
如果OPT(n, v) < OPT(n - 1, v), 那么任何从v到t的最短路径都包含一个环W,并且,W包含负数的权值边。
以上两条可以用于检测负环。Bellman-Ford算法的时间复杂度为O(mn), 空间复杂度为O(m+n).
第二部分:所有点对之间的最短路径
最短路径包含单源最短路径问题和所有点对之间的最短路径问题。单源最短路径问题包含非负边权重的Dijkstra算法(O(E+VlgV)),一般算法Bellman-Ford算法(O(VE)) 和 DAG算法一种Bellman-Ford的变化(O(V+E))。所有点对之间的最短路径问题则包括,Dijkstra算法|V|次:O(VE+V2lgV), 和一般方法(下面要介绍的三种算法)。
给出一个图G=(V, E), |V| = n, 边和权重之间的函数关系为w: E→R. 输出为最短路径长度的nxn的矩阵,对于所有的i, j ∈V。
考虑在每一个顶点运行一次Bellman-Ford算法,时间为O(V2E)
动态规划
考虑一个有向图nxn的邻接矩阵,定义为从i到j使用最多m条边的一个最短路径的权重。因为我们得到
对于任意m = 1,2,…,n-1,
要证明以上式子,可以对进行条件松弛,对于任意的k从1到n,如果,那么就将dij更新为
没有负环就意味着,
以下为所有点对之间的一半情况的三种算法:
1. 矩阵乘法
计算C=A · B, 其中C,A和B都为nxn的矩阵,
使用传统的算法需要O(n^3)的时间复杂度。
如果我们将+ 因设为min,将·映射为+, 那么有
这样,
单位矩阵I表示为
(min,+)乘法是关联的,在实数中,它形成了一种集合结构叫做闭合半环。因此,我们可以计算
得出,
时间复杂度为,并不比n倍的Bellman-Ford算法好。
因此,一种改进的矩阵乘法算法是,不停平方,
这样,只需要计算O(lgn)次的平方,
时间复杂度变为
为了检测是否存在负权重环,需要检查对角线是否含有负值需要额外的O(n)的时间。
2. Floyd-Warshall算法
该算法也是一个动态规划,但是有着更快的速度。
定义是从i到j包含集合为{1,2,…k}为中间结点的最短路径的权重
那么有,,且,
寻找最段路径的过程中会发生
循环为
时间复杂度为,并且更加有效。
3. Johnson算法
对每一个v∈V,给定一个标签h(v),重新给每一条边(u, v)∈E赋予权重
这样,相同的两个顶点之间的路径将会被相同的值被重新赋权重。
A.找到一个标记为h的顶点,使得对于所有的(u, v)∈E成立通过使用Bellman-Ford算法来解决不同限制
或者决定一个负权重环是否存在,所需时间为O(VE).
B.对于每一个使用的顶点运行Dijsktra算法,时间复杂度
C.对每一个最短路径长度重新赋权值产生原始图的最短路径长度,时间复杂度为
因此,总的时间为
第三部分 网络流
最大流和最小切割是两个非常常见的算法问题。
最小切割问题:
可以抽象为通过边的材料流动。
有向图G=(V, E)没有平行的边,两个不同的结点s为source,t为sink,c(e)是边e的容量。
定义s-t切割是s∈A,t∈B的V的一个划分(A,B)。cut (A,B)的容量是
因此,最小s-t划分问题就是找到有着最小容量的一个s-t划分。
流的问题则为:
首先定义s-t流是一个满足一下条件的函数:
对于每一条边e∈E:;对于每一个顶点v∈V-{s,t},
流f的值定义为,如下图所示
因此最大流问题就是找到s-t流的最大值。
流值定理为:令f是任意的一个流,(A, B)是任意的s-t cut。那么,通过cut传送的网络流等于总的离开s的量,即
以下为一个形象的例子:
弱对偶性:令f是任意的一个流,(A, B)是任意的s-t cut。那么,流的值最多为cut的容量,即v(f) <= cap(A, B)
推论为:如果v(f) = cap(A, B), 那么f是最大的流,(A, B)是最小的cut
下面使用贪心算法来寻找一个最大流算法:
首先令所有的边e∈E,都有f(e)=0. 找到一条s-t路径P有每一条边f(e) < c(e)。沿着路径P分割流,重复该操作直到无法进行下去。这里无法再进行下去的含义要注意,局部最优并不能够推出全局最优。
下面介绍一种剩余图,
原始的边为e=(u, v)∈E,流f(e), 容量为c(e). 剩余容量定义为
则剩余图为
剩余边有正的剩余容量,因此,
Ford-Fulkerson算法可以用来找到最大流。也称为分割路径算法。
分割路径定理:如果不存在分割路径算法,流f则为一个最大流。
标签:
原文地址:http://blog.csdn.net/ying_xu/article/details/51375120