网络流学习笔记
网络流学习笔记
前言
怕忘了所以写一下,只记录了最基本的算法,未总结问题模型。
什么是网络流
首先说一下什么是网络流。一张有向图,每条边有边权,代表它的容量。每条边还有流量,流量不能超过对应边的容量,且除了源汇点外,每个点的入边流量之和等于出边流量之和。源点为起点,向外输送流量;汇点为终点,收回由源点发出的所有流量。
可以形象地理解为,网络流就是一张水系图。源点为最高点,也是水的源头。汇点为最低点,也是水的尽头。每条河道连接两个地区,并在每个时刻流过固定量的水,这就是流量。每个河道大小不同,因此每个时刻流过的水量限制也不同,这就是容量。除了源点和汇点外,每个地区都是在每个时刻流进多少水就流出多少,水不作停留。
最大流
什么是最大流
由于每个河道有容量限制,因此每个时刻从源点流出的量也有限制。为每个河道规划合理的流量,使从源点流出最大的流量,就是最大流。
朴素算法
怎样求出最大流?首先考虑一个简单的算法,如果我们在一条河道上增加水,那么这些水一定会继续朝下一个地区流,最终形成一条路径。我们定义残量网络来表示原网络每条边还能增加多少水。若原网络中一条边容量为
这样,我们在网络中添加水的过程可以看作,在残量网络找到一条从源点
重复执行以上算法,直到找不到非
Ford–Fulkerson 算法
但是阻塞流不一定为最大流。可以举个简单的例子,先人工找到最大流,然后执行上述算法,就能发现这个简单算法不一定能找到最大流,因为算法中找路径这一过程是随便乱找的,可能找到错误的路径而错过最优解。
解决方法也很简单,我们为每条边再建一条反边,边权为当前流量。这样每条河道
选择一条路径时,我们不仅要对路径上的边进行减
执行一次以上路径修改的过程,我们成为寻找增广路。每次找增广路一定会使当前最大流增加,每次找路径的时间复杂度为
Edmonds–Karp 算法
这个算法过程与刚才的算法类似,只是每次找路径为从
Dinic 算法
仍然是优化以上算法。算法每轮可能会遍历整个残量网络,但只找出一条增广路,就很浪费。所以我们在一次 bfs 后将点按照最短路长度分成若干层,并只保留相邻层之间的连边(类似于最短路图),这样我们随便走都是最短路了。
有了这张分层图之后,我们尝试不断找多条增广路。考虑 dfs 不重不漏地寻找,并同时更新边权。在 dfs 的过程中,每条边仍可能被遍历特别多次,这又是爆炸的时间复杂度。如果遍历完这条边以下的层之后,上面的层的路径边权最小值仍大于
有了以上思想后,我们为每个点再定义一个
最小割
什么是割
割是一种点的划分方式,将所有点划分在两个集合
最大流最小割定理
引理:任意流小于等于任意割。且取等当且仅当从
最大流最小割定理:最大流等于最小割。
证明略。
寻找最小割
根据以上定理,我们先找到最大流。然后从
割边数量
如果需要在最小割的前提下最小化割边数量,那么先求出最小割,把没有满流的边容量改成
费用流
什么是费用流
在普通网络的基础上,为每条边
SSP 算法
与最大流算法一样,基本思想仍是找增广路进行增广。区别在于,基于贪心思想,我们将路径改为以费用为边权的最短路,也就是将 EK 或 Dinic 算法中的 bfs 改为 spfa。因为反边的边权也要取反,所以存在负边权。用 Dinic 实现时注意 dfs 的过程中可能存在
注意:SSP 算法不能解决单位费用为负的情况,因为可能会存在负环。
上下界网络流
什么是上下界网络流
顾名思义,就是对于每个河道,其流量既有上限也有下限,即流量必须在区间
无源汇上下界可行流
给定边的流量上下界,判断是否存在流,使得所有点均平衡。
考虑转化问我们已知的问题,先将流量限制从
尝试用外力使他重新平衡,定义
如果
有源汇上下界可行流
仍然考虑转化为我们学过的问题,考虑消掉源汇点,连一条由
有源汇上下界最大流
与找可行流一样,我们先连一条由
有源汇上下界最小流
与上一个极其类似,我们跑完可行流后,同样在残量网络中跑一遍