最大流 Ford-Fulkerson 算法
Ford-Fulkerson 算法
基本思想是从任何一个可行流开始,沿增广路径对流进行增广,然后不断重复此过程,直到网络中不存在增广路径为止。
0.流网络G=(V,E)上的一个流的三个条件
- 容量约束: f(u,v)≤c(u,v) 对∀uv∈E成立
- 反对称性: f(u,v) = - f(v,u)
- 守恒约束: 对任意-{}成立
1.剩余网络(余图)
简单来说就是网络的总可承载流量-现有的流量,所得到的剩余网络。
给定图中的流
余图
同样的结点,中间结点和s,t
求余图的流程:
- 对于每条边 满足 > 赋给权重 - (剩余容量)
- 对于每条边 给其逆向边赋给权重 (剩余容量,如果便不赋予)
通俗来讲,就是先把这条边按边的容量方向取反,如果这条边之前存在流量并且没有用完的话,就用总容量-已用流量作为这条边的补,加入剩余网络中。
比如
如下图所示:
以中间那个为例(u到v),u到v的容量是30,实际上只用了20,那么从u到v的管道还剩10,所以剩余网络中就有一条从u到v值为10的边,反向(从v到u)的20是用管道的总容量30减去从u到v的管道10得到的
案例2:剩余网络
2.增广路径
给定一个网络G,令为图的一个流,则称剩余网络,中从到的一条有向路径为增广路径。
就是在剩余网络中从源点到汇点找一条路径
给定图中的流,对应的余图
- 找到余图中的一条新流,该流通过一条没有重复结点的路径并且值和该路径上的最小容量相等(增广路径)
- 沿着路径更新余图
基于之前的余图,找到新的流,如下图所示,为了更好的区分,再放一张之前的余图
对刚才的剩余网络,我们寻找红色标记的一条增广路径如图所示:
如果我们利用增广路径进行扩展的话,显然还是满足容量约束条件的
Ford-Fulkerson 算法思想
从任何一个可行流开始,沿增广路径对流进行增广,然后不断重复此过程,直到网络中不存在增广路径为止。
其伪代码如下:
对于所有e初始化 f(e) = 0
While 余图中存在s-t 路径 P:
沿着路径P增广 f 得到新的 f‘ 和新的余图
沿着P增广 f :
找到路径的最小容量
沿着路径修改权重
3.网络的割
给定一个网络 ,网络中的一个割是把网络G的顶点集V分成两个子集和且s S , t T (一个包含源点,一个包含汇点),
其中流过割的容量记为,定义为割中流过分界线的容量之和
流过割的流量记为 ,定义为割中流过分界线的现有流量之和。
例如:
有推论:
网络G中任意流f的值被G的任意割的容量所限制,即
4.最大流最小割定理
增广路定理:网络达到最大流当且仅当剩余网络中没有增广路径,这也是 Ford-Fulkerson 算法的基础
最小割等于最大流
给定一个网络 ,令 f 为 G 的流,则下列三个
结论相互等价:
- 存在一个割(S, T) ,使得
- f 是G的最大流;
- 剩余网络不存在增广路径
是指在一个网络流中,能够从源点到达汇点的最大流量等于如果从网络中移除就能够导致网络流中断的边的集合的最小容量和。即在任何网络中,最大流的值等于最小割的容量。
形象地理解一下:
好比你家是汇 自来水厂(有需要的同学可以把自来水厂当成银行之类 以下类似)是源
然后自来水厂和你家之间修了很多条水管子接在一起 水管子规格不一 有的容量大 有的容量小
然后问自来水厂开闸放水 你家收到水的最大流量是多少
如果自来水厂停水了 你家那的流量就是0 当然不是最大的流量
但是你给自来水厂交了100w美金 自来水厂拼命水管里通水 但是你家的流量也就那么多不变了 这时就达到了最大流
割集好比是一个*, 把你家和自来水厂之间的水管网络砍断了一些 然后自来水厂无论怎么放水 水都只能从水管断口哗哗流走了 你家就停水了
割的大小应该是*应该关心的事 毕竟细管子好割一些 而最小割花的力气最小
具体的证明分三部分
1.任意一个流都小于等于任意一个割
这个很好理解 自来水公司随便给你家通点水 构成一个流
*随便砍几刀 砍出一个割
由于容量限制 每一根的被砍的水管子流出的水流量都小于管子的容量
每一根被砍的水管的水本来都要到你家的 现在流到外面 加起来得到的流量还是等于原来的流
管子的容量加起来就是割 所以流小于等于割
由于上面的流和割都是任意构造的 所以任意一个流小于任意一个割
2.构造出一个流等于一个割
当达到最大流时 根据增广路定理
剩余网络中s到t已经没有通路了 否则还能继续增广
我们把s能到的的点集设为S 不能到的点集为T
构造出一个割集 S到T的边必然满流 否则就能继续增广
这些满流边的流量和就是当前的流即最大流
把这些满流边作为割 就构造出了一个和最大流相等的割
3.最大流等于最小割
设相等的流和割分别为和
则因为任意一个流小于等于任意一个割
任意≤=≤任意
定理说明完成
##伪代码:
FordFulkerson(G, s, t, c)
//初始化
for 每一条路径 (u,v) ∈E do
f (u,v) ←0 //初始化f(e)=0
Gf ←G //初始化剩余网络
//查找增广路径
while Gf中存在一条增广路径 p do
cf(p)=min{cf(u,v)| uv是p上的边} //cf(p) 作为 p 路径上的最小容量(瓶颈容量)
for each edge (u,v) in p do
f (u,v) ← f (u,v)+ cf(p) //讲选择的增广路径加入图中,更新边的流量
最后还需要更新剩余网络Gf
案例:对于网络:
计算剩余网络:
选择增广路径
然后增加对应的流量即可
之后循环往复,直到找不到新的增广路径即可
1.最多要增广多少次?
可以证明 最多O(VE)次增广 可以达到最大流 证明略
2.如何找到一条增广路?
先明确什么是增广路 增广路是这样一条从s到t的路径 路径上每条边残留容量都为正
把残留容量为正的边设为可行的边 那么我们就可以用简单的BFS得到边数最少的增广路
3.如何增广?
BFS得到增广路之后 这条增广路能够增广的流值 是路径上最小残留容量边决定的
把这个最小残留容量MinCap值加到最大流值Flow上 同时路径上每条边的残留容量值减去MinCap
最后 路径上每条边的反向边残留容量值要加上MinCap
显然算法的运行时间取决于增广路径 p该如何确定,使用BFS或DFS查找增广路径的时间为O(V+E’)=O(E)
可以证明最多使用O(VE)次增广 可以达到最大流,如果算法用BFS选择增广路径(Edmonds-Karp算法) , 则算法的时间复杂度为O()
例题:双核CPU网络流问题
上一篇: jquery如何控制a标签不可点击
下一篇: python怎么下载包
推荐阅读