码迷,mamicode.com
首页 > 编程语言 > 详细

算法课笔记系列(六)—— 图(Part2)

时间:2016-05-12 12:04:19      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:

上一周去了一趟说走就走的治疗之旅,所以算法课都没能上。:( 不过,人生有过这样一次,很足够。只要永远做自己认为对的事情就不会有跨不过去的坎。

跟上周一样,这一周的内容包含几个小部分,分别为最短路径动态规划、所有点对之间的最短路径和网络流。

第一部分:最短路径动态规划

对于一个有向图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则为一个最大流。

 

算法课笔记系列(六)—— 图(Part2)

标签:

原文地址:http://blog.csdn.net/ying_xu/article/details/51375120

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!