何为最大流?
把计算机当做顶点,连接计算机的通信电缆当做边,就可以把该网络就可以把这个网络当作一个有向图来考虑了。图中的每条边都有对应的最大可能的数据传输量,这样,就可以把问题转为如下形式。
- 记每条边对应的实际数据传输量为
- 传输量应该满足以下限制,即通信电缆上传输的数据,不能比传输容量大,否则容易荡机。
- 根据物质守恒定律,除了两个点只负责发送或者接受,其他机器的收发数据量应该是相等的。
- 目标是最大化从发出的数据量。
我们称使得传输量最大的为最大流,而求解最大流的问题为最大流问题。此外,我们称为边的容量,为边的流量,为源点(source), 为汇点(sink)那么,这个问题应该如何求解呢?首先考
虑下面这样的贪心算法。
贪心策略
- 找到一条到的所有路径都满足的边的路径,注意这里是严格的小于。因为对于一个边,如果,那么他已经满了,不能作为一条新的路径使用。
- 如果不存在满足条件的路径,则结束算法。否则,沿着该路径尽可能地增加,返回第(1)步。
将该算法用于样例,得到以下的结果
但是这样得到的结果真的是最大流嘛?事实上,如果采用下图所示的方案,可以得到更优的结果,于是可以知道这个贪心算法是不正确的。
那么,贪心算法得到的结果是10, 而上图得到的结果是11。为了找出二者的区别,不妨来看看它们的流量的差。
反向边的作用,为什么需要反向边?
通过对流量的差的观察可以发现,我们通过将原先得到的流给推回去(图中的-1部分),也就是说给流一个反悔的机会,此时表面上形成了一条新的路径,最大流增加了1,但是仔细思考一下,他到底是怎么运作的呢?难道真的是的一个流嘛?可是事实上并没有路径。
实际上,我们分别考虑这个推回去的流对和他们的影响,对来说,这退回的从的流,由的这个流进行替代,因此流向的流其实没有变化,因此从的最大流没有变化,但是对而言,给它腾出来了一个单位的流,而且这个流刚好可以从流到终点(因为形成了路径,那么其中的一部分肯定也是一条可以使用流量的路径)从流向终点,因此最大流,这就是反向边所起的作用,往往可以从该反向边将路径分成两部分分别进行分析。再分析一个简单的例子
第一步我们得到这条路径,然后更新,如果没有反向边,那就打卡下班,得到一个错误答案(实际上1-2-5-6,1-3-4-6是最优的)。加上反向边,
我们又得到了,细品,也就是3代替2将10个单位的流注入了4,因此形成了新的流,而反悔的10单位的流回到2节点,又经过流向终点,也就是也形成了一个新的流,并且得到了更好的答案。
我们将由反向边和正常边组成的网路称作为残余网络,并称残余网络上的路径为增广路径。
Ford-Fulkerson算法
我们可以试着在之前的贪心算法中加上上面的操作,将算法进行如下改进。
- 只利用满足 的或者满足的对应的反向边, 寻找一条到路径。(边上的其实也就是反向边的容量,也就是说反向边可以用)。
- 如果不存在满足条件的路径,则结束。否则,沿着该路径尽可能地增加流,返回第(1)步。
再将改进后的贪心算法运用于样例。显然就可以了
下面是一个Ford-Fulkerson算法的邻接表实现的例子。这里没有保存的值,取而代之的是直接改变的值。
数据结构
给图中新增边
注意为什么对而言他的反向边是这个,如果是1,那么下一步会push这条反向边进入他的vector,索引值恰好是1。这两条边互为反向边,因此的反向边索引是
DFS寻找增广路径
- 将作为参数,记录该路径上的最大流量,一旦到达终点就可以返回该值。
- 更新容量时记着也要更新反向边的容量。
- 每找到一条增广路径,dfs函数就会返回,used只是在寻找一条增广路经时作为标记使用的。
求解最大流
不断地寻找增广路径,used数组每次都要重新初始化,