最大流、最小割小结

来源:互联网 发布:java编程电脑配置 编辑:程序博客网 时间:2024/06/05 16:24

Part I

网络流问题博大精深,目前我们只学习了其中的一点皮毛,初步认识了最大流问题及其 Edmonds-Karp 算法,了解最小割与最大流之间的联系,初步掌握了利用最大流解决某些二分图匹配问题的方法,因此在这里就谈谈我对网络流的理解。

网络流问题中最经典的是最大流问题,而这也是我们目前学习的重点,就从最大流问题开始叙述。
如图所示,假设需要把一些物品从结点 s(source,称为源点)运送到结点 t(sink,称为汇点),可以从其他结点中转。图 a 中各条有向边的权表示最多能有多少个物品从这条边的起点直接运送到终点。例如,最多可以有 9 个物品从结点 v3 运送到 v2
图 b 展示了一种可能的方案,其中每条边中的第一个数字表示实际运送的物品数目,而第二个数字就是题目中的上限。

这样的问题称为最大流问题(Maximum-Flow Problem)。对于一条边 (u,v),它的物品上限称为容量(capacity),记为 c(u,v)(对于不存在的边(u,v),c(u,v)=0);实际运送的物品称为流量(flow),记为 f(u,v)

首先需要明确,合法的情况必须满足如下限制:

  • 容量限制,对于任意点对 (u,v)0f(u,v)c(u,v)
  • 物品在传输过程中不会额外增加,也不会意外减少,收到的物品数量与发出的物品数量言相等,即对于任意 vV{s,t}eδ_(v)f(e)=eδ+(v)f(e)

目标是最大化从 s 发出的物品数 eδ+(s)f(e)

很显然可以想到一种直观的贪心算法:不断找 st 的一条路径,并发送这条路径上容量最小的边所能承载的物品,直到找不到一条合法路径为止。
例如,对于下面的这个例子:

如果根据上面的贪心算法,先沿着 s12t 传输 5,再沿着 s13t 传输 5,之后就找不到路径了,总流量为 10。

但是,可以举出反例。先沿着 s13t 传输 6,再同时从 s 发出 1 个单位流量到 2,并将在 1 剩下的 4 个单位流量传到 2,从 2 出发总共 5 个单位流向 t,于是总流量为 11。这就是这个图所能得到的最大流。

比较两种策略,我们发现,后一种通过将原先得到的流给“推回去”(在 1 -> 2 这条边)而得到了新的流。因此,我们需要给一个“反悔”的机会。

为了方便,不妨对于每条边,只考虑其 c(e)f(e),即剩余的容量,也称为残量。任意时刻,图中残量不为 0 的边组成的网络被称作残余网络(residual network),该网络上从 st 的路径被称作增广路(augmenting path)。
关于如何“反悔”,具体地,图中的每条有向边 (u,v) 都有一条对应的反向边 (v,u),初始时残量为 0。每当其正向边流了 k 单位的流量,残量减少 k 时,其反向边的残量增加 k,意味着可以有机会“撤销”一部分这次的流,如果将来贪心策略认为这次的选择并不明智的话。其他部分就和贪心策略是一样的,不断在残余网络中寻找一条增广路,并在流的时候对反向边作相应处理,直至找不到增广路为止。

这个算法就是著名的 Ford-Fulkerson 算法,也常被称作 Edmonds-Karp 算法。需要注意的是,由于每次都要寻找增广路,最坏情况下算法效率可能会很低。

为什么该算法是正确的呢?先来介绍最小割问题。
所谓图的割,是指对于某个顶点集合 SV,从 S 出发指向 S 外部(不妨记为 T)的那些边的集合。这些边的容量之和被称为割的容量。
如果有 sS,tVS,这个割也被称作 st 割。将网络中 st 割所包含的边都删去,就不存在从 st 的路径了。

接下来就是证明部分了,思想非常玄妙,并非完全自己打的,参考了一些资料,主要是注重理解,先记下。
对于任意一个割,连接 ST 之间的边的总流量一定是小于等于割的容量(由限制一)。即,对于网络的任意流 f 一定小于等于任意一个割的容量。
而在所有可能的割中,存在一个容量最小的割,我们称其为最小割(minimum cut)。
这个最小割限制了一个网络的流 f 上界,所以有:对于任一个网络流图来说,其最大流一定是小于等于最小割的。

但是这和增广路又有什么关系呢?
利用上面讲的知识,我们可以推出一个最大流最小割定理:(《挑战程序设计竞赛》中也有讲,但我觉得没有下面的直观)
对于一个网络流图 G=(V,E),其中有源点 s 和汇点 t,那么下面三个条件是等价的:

  • f 是图 G 的最大流
  • 残留网络不存在增广路
  • 对于 G 的某一个割 (S,T),此时 f=C(S,T)

首先证明 1 => 2:
我们利用反证法,假设流 f 是图 G 的最大流,但是残留网络中还存在有增广路 p,其流量为 fp。则我们有流 f=f+fp>f。这与 f 是最大流产生矛盾。
接着证明 2 => 3:
因为残留网络不存在增广路,所以在残留网络中不存在路径从 s 到达 t。此时 (S,T) 构成一个割 (S,T)。且对于任意的 uS,vT,有 f(u,v)=c(u,v)。若 f(u,v)<c(u,v),则 s 可以到达 v,与 v 属于 T 矛盾。
因此有 f(S,T)=f(u,v)=c(u,v)=C(S,T)
最后证明 3 => 1:
由于 f 的上界为最小割,当 f 到达割的容量时,显然就已经到达最大值,因此 f 为最大流。
这样就说明了为什么找不到增广路时,所求得的一定是最大流。同时也证明了最小割最大流定理。

Part II

最近针对最小割的练习,我认为其中两道解题的关键都可以归纳为:把题目转化为“总-弃=得”,“总”是一定的,要最大化“得”,就要最小化“弃”,从而得到最小割模型,再根据最小割最大流定理,用所学的最大流算法解决。

除此之外,到目前为止,我们所解的网络流题目(虽然只有五六题)几乎都与二分图有关,无论是匹配还是点独立集等等。这应该是网络流当中很经典也很重要的组成部分,《挑战程序设计竞赛》上有专门介绍相关问题,我粗略看了其中的一部分,但还没有能够完全理解。接下来打算找时间看看,也结合《算法竞赛入门经典训练指南》一起,做做习题。个人感觉到了网络流部分的学习,需要较强的空间抽象思维能力,所以会觉得有些吃力。解题,建对模型是成功的一大半。

关于最大流的求解算法,目前只会 Edmonds-Karp。其实之前自己看过一点 Dinic,但只打了遍模板,没有做题巩固,现在都忘了。这就像我的 kmp 一样,来得快,去得也快,消失得无影无踪。“熟能生巧”真的很有道理,现在叫我打 EK,不用花 3 分钟都可以搞定。但是过了几个月再来看呢?
所以学习一定要自觉复习,才能掌握牢固。而且,为了让自己在遗忘时能回忆起来,一定要写好笔记。我自己也应该持续更新博客,记录学习过程中的点点滴滴。

网络流其实是一个很广的话题,最大流、最小割都还只是其中一个部分。(当然,就这个部分都需要长时间的练习和钻研才能掌握好)还有最小费用流之类的东西,果然还是有很长的路要走。越是到风景壮丽的地方,就会更加的崎岖险阻。希望即使集训结束后也能够自觉坚持,为即将到来的 NOIp 2017 做充分准备。

原创粉丝点击