何为最大流?
把计算机当做顶点,连接计算机的通信电缆当做边,就可以把该网络就可以把这个网络当作一个有向图来考虑了。图中的每条边
e
∈
E
e\in E
e∈E都有对应的最大可能的数据传输量
c
(
e
)
c(e)
c(e),这样,就可以把问题转为如下形式。
- 记每条边对应的实际数据传输量为 f ( e ) f(e) f(e)
- 传输量应该满足以下限制 0 ≤ f ( e ) ≤ c ( e ) 0\leq f(e)\leq c(e) 0≤f(e)≤c(e),即通信电缆上传输的数据,不能比传输容量大,否则容易荡机。
- 根据物质守恒定律,除了 s , t s,t s,t两个点只负责发送或者接受,其他机器的收发数据量应该是相等的。
- 目标是最大化从 s s s发出的数据量。
我们称使得传输量最大的
f
f
f为最大流,而求解最大流的问题为最大流问题。此外,我们称
c
c
c为边的容量,
f
f
f为边的流量,
s
s
s为源点(source),
t
t
t为汇点(sink)那么,这个问题应该如何求解呢?首先考
虑下面这样的贪心算法。
贪心策略
- 找到一条 s s s到 t t t的所有路径都满足 f ( e ) < c ( e ) f(e)<c(e) f(e)<c(e)的边的路径,注意这里是严格的小于。因为对于一个边,如果 f ( e ) = c ( e ) f(e)=c(e) f(e)=c(e),那么他已经满了,不能作为一条新的路径使用。
- 如果不存在满足条件的路径,则结束算法。否则,沿着该路径尽可能地增加
c
(
e
)
c(e)
c(e),返回第(1)步。
将该算法用于样例,得到以下的结果
但是这样得到的结果真的是最大流嘛?事实上,如果采用下图所示的方案,可以得到更优的结果,于是可以知道这个贪心算法是不正确的。
那么,贪心算法得到的结果是10, 而上图得到的结果是11。为了找出二者的区别,不妨来看看它们的流量的差。
反向边的作用,为什么需要反向边?
通过对流量的差的观察可以发现,我们通过将原先得到的流给推回去(图中的-1部分),也就是说给流一个反悔的机会,此时表面上 s − 2 − 1 − 3 − t s-2-1-3-t s−2−1−3−t形成了一条新的路径,最大流增加了1,但是仔细思考一下,他到底是怎么运作的呢?难道真的是 2 → 1 2\rightarrow 1 2→1的一个流嘛?可是 2 → 1 2\rightarrow 1 2→1事实上并没有路径。
实际上,我们分别考虑这个推回去的流对
1
1
1和
2
2
2他们的影响,对
2
2
2来说,这退回的从
1
→
2
1\rightarrow 2
1→2的流,由
s
→
2
s\rightarrow2
s→2的这个流进行替代,因此流向
2
2
2的流其实没有变化,因此从
2
→
t
2\rightarrow t
2→t的最大流没有变化,但是对
1
1
1而言,给它腾出来了一个单位的流,而且这个流刚好可以从
1
−
3
−
t
1-3-t
1−3−t流到终点(因为
s
−
2
−
1
−
3
−
t
s-2-1-3-t
s−2−1−3−t形成了路径,那么其中的一部分肯定也是一条可以使用流量
1
1
1的路径)从
1
−
3
−
t
1-3-t
1−3−t流向终点,因此最大流
+
1
+1
+1,这就是反向边所起的作用,往往可以从该反向边将路径分成两部分分别进行分析。再分析一个简单的例子
第一步我们得到
1
−
2
−
4
−
6
1-2-4-6
1−2−4−6这条路径,然后更新,如果没有反向边,那就打卡下班,得到一个错误答案(实际上1-2-5-6,1-3-4-6是最优的)。加上反向边,
我们又得到了
1
−
3
−
4
−
2
−
5
−
6
1-3-4-2-5-6
1−3−4−2−5−6,细品,也就是3代替2将10个单位的流注入了4,因此
1
−
3
−
4
−
6
1-3-4-6
1−3−4−6形成了新的流,而反悔的10单位的流回到2节点,又经过
5
−
6
5-6
5−6流向终点,也就是
1
−
2
−
5
−
6
1-2-5-6
1−2−5−6也形成了一个新的流,并且得到了更好的答案。
我们将由反向边和正常边组成的网路称作为残余网络,并称残余网络上
s
→
t
s\rightarrow t
s→t的路径为增广路径。
Ford-Fulkerson算法
我们可以试着在之前的贪心算法中加上上面的操作,将算法进行如下改进。
- 只利用满足 f ( e ) < c ( e ) f(e)<c(e) f(e)<c(e) 的 e e e或者满足 f ( e ) > 0 f(e)>0 f(e)>0的 e e e对应的反向边 r e v ( e ) rev(e) rev(e), 寻找一条 s s s到 t t t路径。(边上的 f ( e ) f(e) f(e)其实也就是反向边的容量, f ( e ) > 0 f(e)>0 f(e)>0也就是说反向边可以用)。
- 如果不存在满足条件的路径,则结束。否则,沿着该路径尽可能地增加流,返回第(1)步。
再将改进后的贪心算法运用于样例。显然就可以了
下面是一个Ford-Fulkerson算法的邻接表实现的例子。这里没有保存
f
(
e
)
f(e)
f(e)的值,取而代之的是直接改变
c
(
e
)
c(e)
c(e)的值。
数据结构
给图中新增边
注意为什么对
f
r
o
m
from
from而言他的反向边是这个
G
[
t
o
]
.
s
i
z
e
G[to].size
G[to].size,如果
G
[
t
o
]
.
s
i
z
e
G[to].size
G[to].size是1,那么
G
[
t
o
]
G[to]
G[to]下一步会push这条反向边进入他的vector,索引值恰好是1。
f
r
o
m
<
=
>
t
o
from<=>to
from<=>to这两条边互为反向边,因此
G
[
t
o
]
G[to]
G[to]的反向边索引是
G
[
f
r
o
m
]
.
s
i
z
e
(
)
−
1
G[from].size()-1
G[from].size()−1
DFS寻找增广路径
- 将 f f f作为参数,记录该路径上的最大流量,一旦到达终点就可以返回该值。
- 更新容量时记着也要更新反向边的容量。
- 每找到一条增广路径,dfs函数就会返回,used只是在寻找一条增广路经时作为标记使用的。
求解最大流
不断地寻找增广路径,used数组每次都要重新初始化,
最小割问题
什么是最小割问题?对于给定网络,为了保证没有从s到t的路径,需要删去的边的总容量的最小值是多少?
下面介绍网络流理论中一个最为重要的定理
最大流最小割定理(Maximum Flow, Minimum Cut Theorem):
网络的最大流等于最小割
具体的证明分三部分
具体的证明分三部分
1.任意一个流都小于等于任意一个割 这个很好理解 自来水公司随便给你家通点水 构成一个流 恐怖分子随便砍几刀 砍出一个割 由于容量限制 每一根的被砍的水管子流出的水流量都小于管子的容量 每一根被砍的水管的水本来都要到你家的 现在流到外面 加起来得到的流量还是等于原来的流
管子的容量加起来就是割 所以流小于等于割 由于上面的流和割都是任意构造的 所以任意一个流小于任意一个割
2.构造出一个流等于一个割 当达到最大流时 根据增广路定理 残留网络中s到t已经没有通路了 否则还能继续增广 我们把s能到的的点集设为S 不能到的点集为T 构造出一个割集C[S,T] S到T的边必然满流 否则就能继续增广 这些满流边的流量和就是当前的流即最大流
把这些满流边作为割 就构造出了一个和最大流相等的割
3.最大流等于最小割 设相等的流和割分别为Fm和Cm 则因为任意一个流小于等于任意一个割 任意F≤Fm=Cm≤任意C 定理说明完成,证明如下: 对于一个网络流图G=(V,E),其中有源点s和汇点t,那么下面三个条件是等价的:
- 流f是图G的最大流
- 残留网络Gf不存在增广路
- 对于G的某一个割(S,T),此时f = C(S,T) 首先证明1 => 2:
我们利用反证法,假设流f是图G的最大流,但是残留网络中还存在有增广路p,其流量为fp。则我们有流f’=f+fp>f。这与f是最大流产生矛盾。
接着证明2 => 3:
假设残留网络Gf不存在增广路,所以在残留网络Gf中不存在路径从s到达t。我们定义S集合为:当前残留网络中s能够到达的点。同时定义T=V-S。
此时(S,T)构成一个割(S,T)。且对于任意的u∈S,v∈T,有f(u,v)=c(u,v)。若f(u,v) < c(u,v),则有Gf(u,v) > 0,s可以到达v,与v属于T矛盾。
因此有f(S,T)=Σf(u,v)=Σc(u,v)=C(S,T)。 最后证明3 => 1:
由于f的上界为最小割,当f到达割的容量时,显然就已经到达最大值,因此f为最大流。 这样就说明了为什么找不到增广路时,所求得的一定是最大流。