何为最大流?

网络流学习笔记(1):最大流及其反向边详解
把计算机当做顶点,连接计算机的通信电缆当做边,就可以把该网络就可以把这个网络当作一个有向图来考虑了。图中的每条边eEe\in E都有对应的最大可能的数据传输量c(e)c(e),这样,就可以把问题转为如下形式。

  • 记每条边对应的实际数据传输量为f(e)f(e)
  • 传输量应该满足以下限制0f(e)c(e)0\leq f(e)\leq c(e),即通信电缆上传输的数据,不能比传输容量大,否则容易荡机。
  • 根据物质守恒定律,除了s,ts,t两个点只负责发送或者接受,其他机器的收发数据量应该是相等的。
  • 目标是最大化从ss发出的数据量。

我们称使得传输量最大的ff最大流,而求解最大流的问题为最大流问题。此外,我们称cc为边的容量,ff为边的流量,ss为源点(source), tt为汇点(sink)那么,这个问题应该如何求解呢?首先考
虑下面这样的贪心算法。

贪心策略

  • 找到一条sstt的所有路径都满足f(e)<c(e)f(e)<c(e)的边的路径,注意这里是严格的小于。因为对于一个边,如果f(e)=c(e)f(e)=c(e),那么他已经满了,不能作为一条新的路径使用。
  • 如果不存在满足条件的路径,则结束算法。否则,沿着该路径尽可能地增加c(e)c(e),返回第(1)步。
    将该算法用于样例,得到以下的结果
    网络流学习笔记(1):最大流及其反向边详解
    但是这样得到的结果真的是最大流嘛?事实上,如果采用下图所示的方案,可以得到更优的结果,于是可以知道这个贪心算法是不正确的。
    网络流学习笔记(1):最大流及其反向边详解
    那么,贪心算法得到的结果是10, 而上图得到的结果是11。为了找出二者的区别,不妨来看看它们的流量的差。
    网络流学习笔记(1):最大流及其反向边详解

反向边的作用,为什么需要反向边?

通过对流量的差的观察可以发现,我们通过将原先得到的流给推回去(图中的-1部分),也就是说给流一个反悔的机会,此时表面上s213ts-2-1-3-t形成了一条新的路径,最大流增加了1,但是仔细思考一下,他到底是怎么运作的呢?难道真的是212\rightarrow 1的一个流嘛?可是212\rightarrow 1事实上并没有路径。

实际上,我们分别考虑这个推回去的流对1122他们的影响,对22来说,这退回的从121\rightarrow 2的流,由s2s\rightarrow2的这个流进行替代,因此流向22的流其实没有变化,因此从2t2\rightarrow t的最大流没有变化,但是对11而言,给它腾出来了一个单位的流,而且这个流刚好可以从13t1-3-t流到终点(因为s213ts-2-1-3-t形成了路径,那么其中的一部分肯定也是一条可以使用流量11的路径)从13t1-3-t流向终点,因此最大流+1+1,这就是反向边所起的作用,往往可以从该反向边将路径分成两部分分别进行分析。再分析一个简单的例子
网络流学习笔记(1):最大流及其反向边详解
第一步我们得到12461-2-4-6这条路径,然后更新,如果没有反向边,那就打卡下班,得到一个错误答案(实际上1-2-5-6,1-3-4-6是最优的)。加上反向边,
网络流学习笔记(1):最大流及其反向边详解
我们又得到了1342561-3-4-2-5-6,细品,也就是3代替2将10个单位的流注入了4,因此13461-3-4-6形成了新的流,而反悔的10单位的流回到2节点,又经过565-6流向终点,也就是12561-2-5-6也形成了一个新的流,并且得到了更好的答案。
我们将由反向边和正常边组成的网路称作为残余网络,并称残余网络上sts\rightarrow t的路径为增广路径

Ford-Fulkerson算法

我们可以试着在之前的贪心算法中加上上面的操作,将算法进行如下改进。

  • 只利用满足f(e)<c(e)f(e)<c(e)ee或者满足f(e)>0f(e)>0ee对应的反向边rev(e)rev(e), 寻找一条sstt路径。(边上的f(e)f(e)其实也就是反向边的容量,f(e)>0f(e)>0也就是说反向边可以用)。
  • 如果不存在满足条件的路径,则结束。否则,沿着该路径尽可能地增加流,返回第(1)步。

再将改进后的贪心算法运用于样例。显然就可以了
网络流学习笔记(1):最大流及其反向边详解
下面是一个Ford-Fulkerson算法的邻接表实现的例子。这里没有保存f(e)f(e)的值,取而代之的是直接改变c(e)c(e)的值。

数据结构

网络流学习笔记(1):最大流及其反向边详解

给图中新增边

注意为什么对fromfrom而言他的反向边是这个G[to].sizeG[to].size,如果G[to].sizeG[to].size是1,那么G[to]G[to]下一步会push这条反向边进入他的vector,索引值恰好是1。from<=>tofrom<=>to这两条边互为反向边,因此G[to]G[to]的反向边索引是G[from].size()1G[from].size()-1
网络流学习笔记(1):最大流及其反向边详解

DFS寻找增广路径
  • ff作为参数,记录该路径上的最大流量,一旦到达终点就可以返回该值。
  • 更新容量时记着也要更新反向边的容量。
  • 每找到一条增广路径,dfs函数就会返回,used只是在寻找一条增广路经时作为标记使用的。

网络流学习笔记(1):最大流及其反向边详解

求解最大流

不断地寻找增广路径,used数组每次都要重新初始化,
网络流学习笔记(1):最大流及其反向边详解

相关文章:

  • 2021-09-25
  • 2021-08-29
  • 2021-11-18
  • 2021-06-23
  • 2021-07-19
  • 2021-09-21
猜你喜欢
  • 2021-12-23
  • 2021-07-06
  • 2021-12-23
  • 2022-01-30
  • 2021-05-23
  • 2021-12-23
  • 2022-12-23
相关资源
相似解决方案