第十五关——网络流

09:32:33 我没想到,为了你我能疯狂到。——邓紫棋《光年之外》

网络流(network-flows)

  • 相关概念

好比你家是汇自来水厂是源,然后自来水厂和你家之间修了很多条水管子接在一起,水管子规格不一,有的容量大,有的容量小然后问自来水厂开闸放水,你家收到水的最大流量是多少如果自来水厂停水了,你家那的流量就是0,当然不是最大的流量但是你给自来水厂交了100w美金,自来水厂拼命水管里通水,但是你家的流量也就那么多不变了,这时就达到了最大流

是一种类比水流的解决问题方法,与线性规划密切相关。

假设G(V,E) 是一个有限的有向图,它的每条边(u,v)∈E都有一个非负值实数的容量c(u,v) 。如果(u,v)不属于E,我们假设c(u,v) = 0 。我们区别两个顶点:一个源点s和一个汇点t

一道网络流是一个对于所有结点uv都有以下特性的实数函数f:V×V→R

边的剩余容量 (Residual Capacity)是cf(u,v) =c(u,v)−f(u,v)。这定义了以Gf(V,Ef)表示的剩余网络 (Residual Network),它显示可用的容量的多少。留意就算在原网络中由uv没有边,在剩余网络乃可能有由uv的边。因为相反方向的流抵消,减少由v到u的流等于增加由uv的流。

扩张路径 (Augmenting Path)是一条路径 (u1,u2...uk),而u1 =suk=tcf(ui,ui+ 1) > 0,这表示沿这条路径传送更多流是可能的。

  • 最大流问题

1、augment path,直译为“增广路径”,其思想大致如下:

原有网络为G,设有一辅助图G',其定义为V(G') = V(G),E(G')初始值(也就是容量)与E(G)相同。每次操作时从Source点搜索出一条到Sink点的路径,然后将该路径上所有的容量减去该路径上容量的最小值,然后对路径上每一条边<u,v>添加或扩大反方向的容量,大小就是刚才减去的容量。一直到没有路为止。此时辅助图上的正向流就是最大流。

很容易觉得这个算法会陷入死循环,但事实上不是这样的。只需要注意到每次网络中由Source到Sink的流都增加了,若容量都是整数,则这个算法必然会结束。

寻找通路的时候可以用DFS,BFS最短路等算法。就这两者来说,BFS要比DFS快得多,但是编码量也会相应上一个数量级。

增广路方法可以解决最大流问题,然而它有一个不可避免的缺陷,就是在极端情况下每次只能将流扩大1(假设容量、流为整数),这样会造成性能上的很大问题,解决这个问题有一个复杂得多的算法,就是预推进算法。

2、push label,直译为“预推进”算法。

3、压入与重标记(Push-Relabel)算法

除了用各种方法在剩余网络中不断找增广路(augmenting)的Ford-Fulkerson系的算法外,还有一种求最大流的算法被称为压入与重标记(Push-Relabel)算法。它的基本操作有:压入,作用于一条边,将边的始点的预流尽可能多的压向终点;重标记,作用于一个点,将它的高度(也就是label)设为所有邻接点的高度的最小值加一。Push-Relabel系的算法普遍要比Ford-Fulkerson系的算法快,但是缺点是相对难以理解。

Relabel-to-Front使用一个链表保存溢出顶点,用Discharge操作不断使溢出顶点不再溢出。Discharge的操作过程是:若找不到可被压入的临边,则重标记,否则对临边压入,直至点不再溢出。算法的主过程是:首先将源点出发的所有边充满,然后将除源和汇外的所有顶点保存在一个链表里,从链表头开始进行Discharge,如果完成后顶点的高度有所增加,则将这个顶点置于链表的头部,对下一个顶点开始Discharge。

Relabel-to-Front算法的时间复杂度是O(V^3),还有一个叫Highest Label Preflow Push的算法复杂度据说是O(V^2*E^0.5)。因为Relabel-to-Front每次前移的都是高度最高的顶点,所以也相当于每次选择最高的标号进行更新。还有一个感觉也会很好实现的算法是使用队列维护溢出顶点,每次对pop出来的顶点discharge,出现了新的溢出顶点时入队。

Push-Relabel类的算法有一个名为gap heuristic的优化,就是当存在一个整数0<k<V,没有任何顶点满足h[v]=k时,对所有h[v]>k的顶点v做更新,若它小于V+1就置为V+1。

  • 最小费用问题

一.Ford和Fulkerson迭加算法

基本思路:把各条弧上单位流量的费用看成某种长度,用求解最短路问题的方法确定一条自V1至Vn的最短路;在将这条最短路作为可扩充路,用求解最大流问题的方法将其上的流量增至最大可能值;而这条最短路上的流量增加后,其上各条弧的单位流量的费用要重新确定,如此多次迭代,最终得到最小费用最大流。

  • 迭加算法:

1) 给定目标流量F或∞,给定最小费用的初始可行流=0。

2) 若V(f)=F,停止,f为最小费用流;否则转(3)。

3) 构造相应的新的费用有向图W(fij),在W(fij)寻找Vs到Vt的最小费用有向路P(最短路),沿P增加流f的流量直到F,转(2);若不存在从Vs到Vt的最小费用的有向路P,停止。f就是最小费用最大流。

最大流问题仅注意网络流的流通能力,没有考虑流通的费用。实际上费用因素是很重要的。例如在交通运输问题中,往往要求在完成运输任务的前提下,寻求一个使总运输费用最省的运输方案,这就是最小费用流问题。如果只考虑单位货物的运输费用,那么这个问题就变成最短路问题。由此可见,最短路问题是最小费用流问题的基础。现已有一系列求最短路的成功方法。最小费用流(或最小费用最大流)问题 ,可以交替使用求解最大流和最短路两种方法,通过迭代得到解决。

二. 圈算法:

1) 利用Ford和Fulkson标号算法找出流量为F(<=最大流)的流f。

2) 构造f对应的调整容量的流网络N'(f)。

3) 搜索N'(f)中的负费用有向图C(Floyd算法),若没有则停止,否则转(4)。

4) 在C上找出最大的循环流,并加到N上去,同时修改N'(F)中C的容量,转(3)。

三. ZKW费用流

费用流是网络流的一个很重要的组成部分,也是非常有用的一种图论模型,关于费用流的算法,流传比较广的主要是消圈和增广路算法,而近来炒得沸沸扬扬的ZKW算法也是一种非常优秀的算法,这里我就谈谈我对此算法的一些理解。

此算法是由ZKW大牛创立,主要思想仍然是找增广路,只是有了一些优化在里边。原来我们找增广路主要是依靠最短路算法,如SPFA。因此此算法的时间复杂度主要就取决于增广的次数和每次增广的耗费。由于每一次找增广路是都是重新算一遍,这样似乎显得有些浪费,如果我们能够缩短找增广路的时间,那必定会大大地优化算法。

值得注意的是,在寻求最短路得过程中,设dis[i]为i到起点的距离,对于每一条由i引向j的边,必有dis[j]<=dis[i]+map[i][j];既然满足这样的恒等式,我们就可以借用KM算法的调整思想来寻求最短路,每次只走dis[j]=dis[i]+map[i][j]的路径,一旦不存在到达终点的路径,就扫描每一条边,找到最小的距离增加值,使得有至少一条新边被加入相等子图。

  • 算法流程如下:

1.将dis数组清零,表示当前的相等子图内只有起点。(如果存在负权边,必须要用spfa跑一遍,初始化出dis数组)。

2.深搜,如果到达终点,全部回退更改流量,再进行步骤2;否则,转3。

3.修改dis的值,如果无法修改,结束程序,已经找到的答案,反之转2。

有上下界

上面讨论的网络流都只对每条弧都限定了上界(其实其下界可以看成0),现在给每条弧<Vi, Vj>加上一个下界限制Aij (即必须满足Aij≤fij)。

弧上数字对第一个是上界,第二个是下界。若是撇开下界不看,此图的最大流如图(a)所示,流量是6;但若是加入了下界的限制,它的最大流量就只有5了。

  • 链与增广路

在容量网络 G(V, E) 中, 设有一可行流 f = { f(u, v) }, 根据每条弧上流量的多少、以及流量和容量的关系,可将弧分四种类型:

饱和弧, 即 f(u,v)=c(u,v);

非饱和弧,即 f(u,v)<c(u,v);

零流弧, 即 f(u,v)=0;

非零流弧, 即 f(u,v)>0。

链: 在容量网络中,称顶点序列(u,u1,u2,…,un,v)为一条链,要求相邻两个顶点之间有一条弧, 如 <u, u1> 或 <u1, u> 为容量网络中一条弧。沿着 Vs 到 Vt 的一条链, 各弧可分为两类:

前向弧: 方向与链的正方向一致的弧, 其集合记为 P+;

后向弧: 方向与链的正方向相反的弧, 其集合记为 P-;

增广路: 设 f 是一个容量网络 G 中的一个可行流, P 是从 Vs 到 Vt 的一条链, 若 P 满足下列条件:

在 P 的所有前向弧 <u, v> 上, 0≤f(u,v)<c(u,v), 即 P+ 中每一条弧都是非饱和弧;

在 P 的所有后向弧 <u, v> 上, 0<f(u,v)≤c(u,v), 即 P– 中每一条弧是非零流弧。

则称 P 为关于可行流 f 的一条增广路, 简称为 增广路(或称为增广链、可改进路)。沿着增广路改进可行流的操作称为增广

残留容量与残留网络

残留容量: 给定容量网络 G(V, E) 及可行流 f, 弧 <u, v> 上的残留容量记为 c′(u,v)=c(u,v)–f(u,v)。每条弧的残留容量表示该弧上可以增加的流量。因为从顶点 u 到顶点 v 流量的减少, 等效于顶点 v 到顶点 u 流量增加, 所以每条弧 <u, v> 上还有一个反方向的残留容量 c′(v,u)=–f(u,v)。

一个容量网络中还可以压入的流量称为残留容量

残留网络: 设有容量网络 G(V, E) 及其上的网络流 f,G 关于 f 的残留网络(简称残留网络)记为 G'(V', E'), 其中 G’的顶点集 V’和 G 的顶点集 V 相同,即 V’=V, 对于 G 中的任何一条弧 <u, v>, 如果 f(u,v)<c(u,v), 那么在 G’中有一条弧 <u, v>∈E', 其容量为 c′(u,v)=c(u,v)–f(u,v), 如果 f(u,v)>0,则在 G’中有一条弧 <v, u>∈E', 其容量为 c′(v,u)=f(u,v), 残留网络也称为剩余网络.

由残留的容量以及源点汇点构成的网络。
  • 博客推荐

1.详细

2.有趣(也不是很有趣)

10:15:38 还记得那年秋天说了再见。——周杰伦《手写的从前》

原文地址:https://www.cnblogs.com/wybxz/p/12825528.html