网络流学习笔记

本篇文章中的所有模板题代码

网络流的概念及定理

  • 流网络

流网络是指一个有向图 \(G\),由点集 \(V\) 和边集 \(E\) 组成,其中有一个源点 \(s\) 和一个汇点 \(t\)。每条边有一个属性称为容量 \(c(u,v)\),每条边也有一个流量 \(f(u,v)\),边的流量大于等于 \(0\) 且小于等于这条边的容量,也就是 \(0 \le f(u,v) \le c(u,v)\)。(不考虑反向边)

如果把流网络抽象成很多根水管组成的运水装置的话,那么边的容量就是这根水管的最大承受的进水量,边的流量就相当于这根水管的实际进水量。

  • 可行流

流网络的一个 可行流 \(f\) 是指满足容量限制和流量守恒的流。

  1. 容量限制:每条边的流量大于等于 \(0\) 且小于等于容量。
  2. 流量守恒:对于除了源点和汇点的所有点,必须满足进去的流量等于出去的流量。相当于中间的点上不会留着水,只有源点在源源不断地流出,汇点在源源不断地进水。

可以把一组可行流抽象成源点源源不断地向流网络里面流水,通过中间的边最终流到汇点的过程。

可行流的流量是指从源点流出的流量减去流入源点的流量(其实就是从源点净流出的流量)。最大流指的就是流量最大的可行流。

  • 残留网络

残留网络是通过原网络的一个可行流 \(f\) 决定的。它的点集和原网络相同,边集不仅包含了原网络的所有边,还包含了原网络的所有边的反向边。其中和原网络方向相同的边的容量等于原网络中该边的容量减去该边在当前可行流 \(f\) 中的流量(也就是原网络中该边还能再增加的流量),和原网络反向的边的容量等于该边在当前可行流中的流量(也就是原网络中该边还能再减少的流量)。

注意:只有在残留网络中才考虑反向边,在原网络中不考虑!

有一个很重要的性质:原网络的一个可行流加上这个可行流对应的残留网络上的一个可行流之后一定还是原网络的一个可行流。其中两个可行流相加是指加上同向边的流量,减去反向边的流量。并且得到的新的可行流的流量等于原可行流流量加上残留网络上可行流流量。

这个性质使我们发现,如果残留网络中存在一个流量大于 \(0\) 的可行流的话,那么原网络中的那个可行流一定不是最大流,因为还可以加上残留网络中的那个可行流的流量(大于 \(0\))使得原网络的流量更大。

技巧:想求原网络中正向边的流量等价于求残留网络中它的反向边的容量。

  • 增广路

增广路是指在残留网络中,一条从源点 \(s\) 到汇点 \(t\) 的路径,满足路径上经过的每一条边的容量大于 \(0\)

显然,如果存在增广路的话,那么一定也存在流量大于 \(0\) 的可行流,这又说明了原网络的当前可行流不是最大流。反过来如果不存在增广路的话,那么当前可行流一定就是最大流。

将原网络的点集分为两个,\(S\)\(T\)。其中源点 \(s\)\(S\) 中,汇点 \(t\)\(T\) 中,且 \(S\)\(T\) 的交集为空,并集为所有点(相当于如果把这两个点集之间的边删掉,则 \(S\)\(T\) 不连通)。割的容量是指所有从 \(S\)\(T\) 的边的容量(不考虑反向边,也就是不考虑从 \(T\)\(S\) 的边),割的流量是指所有从 \(S\)\(T\) 的边的流量减去所有从 \(T\)\(S\) 的边的流量(也就是要考虑反向边)。最小割指的就是最小割的容量。

性质一:对于任意一个割,割的流量一定等于小于割的容量。

证明:因为所有 \(S\)\(T\) 的边的流量已经小于等于所有 \(S\)\(T\) 中的边的容量了,再减去从 \(T\)\(S\) 的流量之后一定还会变得更小。

性质二:任意一个割的流量都等于对应原网络的流量。

证明:因为原网络的流量等于流进 \(s\) 的流量减去流出 \(s\) 的流量,而所有流进 \(s\) 的最终都会从 \(S\) 流到 \(T\)(也就是 \(S\)\(T\) 割边的流量),流进 \(s\) 的都是从 \(T\) 流进 \(S\) 的(也就是 \(T\)\(S\) 割边的流量),所以从 \(s\) 净流出流量的就等于这两者相减(也就是割的流量)。

通过上面的两个性质,我们会得到一个很重要的结论:对于原网络的任意一个可行流,和任意一个割,都满足可行流的流量小于等于割的容量,因为割的容量 \(\ge\) 割的流量 \(=\) 可行流流量。也就是最大流 \(\le\) 最小割。

  • 最大流最小割定理

最大流最小割定理:只要下述条件中的任意一个满足,那么其它两个条件则必然满足。

  1. 可行流 \(f\) 是最大流。(一)
  2. 可行流 \(f\) 的残留网络中不存在增广路。(二)
  3. 存在一个割使得可行流 \(f\) 的流量等于割的容量。(三)

考虑证明,我们只需要证明(一)能推(二),(二)能推(三),(三)能推(一) 即可证明到上述结论。

(一)推(二):用反证法,如果残留网络中存在增广路的话,那么将可以将增广路加到原可行流上,这样原可行流的流量一定会变大,与原可行流是最大流不符。

(二)推(三):我们可以构造一种方案,使得(三)成立。首先将点分为 \(S\)\(T\),其中 \(S\) 中包含了在残留网络中所有从源点出发,经过容量大于 \(0\) 的边能到达的点。因为不存在增广路,所以汇点一定不在 \(S\) 中。\(T\) 包含了所有其他点。这一定满足 \(s\)\(S\) 中,\(t\)\(T\) 中。考虑计算这个割的流量。先计算 \(S\)\(T\) 的边,我们会发现,每一条从 \(S\)\(T\) 的边的流量一定等于这条边的容量,否则在残留网络中这条边的容量大于 \(0\),与定义不符。再计算 \(T\)\(S\) 的边,我们会发现,这些边的流量一定为都零,否则在残留网络中这些边的反向边的容量大于 \(0\),与定义不符。所以可行流的流量 \(=\) 割的流量 \(=\)\(S\)\(T\) 的边的流量减去从 \(T\)\(S\) 的边的流量 \(=\)\(S\)\(T\) 的边的容量减去 \(0\) \(=\) 割的容量。于是得到可行流 \(f\) 的流量等于这个割的容量,得证。

(三)推(一):证明 \(A=B\) 只需证明 \(A \le B\) 并且 \(B \le A\)。显然可行流 \(\le\) 最大流。在(三)的条件下,因为可行流的流量等于割的容量,且最大流 \(\le\) 最小割 \(\le\) 当前割的容量 \(=\) 可行流,所以可行流 \(\ge\) 最大流,所以可行流等于最大流。

所以最大流最小割定理成立。

那我们再推导一下,最大流是不是等于最小割呢?已知最大流 \(\le\) 最小割。而最大流 \(\ge\) 可行流 \(=\) 某一个割的容量 \(\ge\) 最小割,所以最大流 \(\ge\) 最小割,所以最大流等于最小割。

  • \(\text{Ford Fulkerson}\) 方法

Ford Fulkerson 方法是一种解决最大流问题的方法。它是指:因为我们知道如果流 \(f\) 是最大流,那么不存在增广路。那么如果存在增广路,则一定不是最大流。所以我们每一次可以在残留网络中找增广路,如果找到了就将它加到原可行流中,并且更新残留网络的边的容量(因为可行流变了),然后循环继续执行此操作。如果找不到的话(说明已经是最大流了)就停止。

实现 FF 的算法主要有两种,一种是 EK 算法,另外一种是 Dinic 算法。一般来说 Dinic 比 EK 要快一些。

网络流之 \(\text{EK}\) 算法

模板题:P3376 【模板】网络最大流

直接模拟 \(\text{Ford Fulkerson}\) 的过程即可。外面套一个循环,每一次用 bfs 去找增广路,并且存下这一条增广路的所有边,如果找不到就 break,找到了就更新答案和残留网络。注意我们维护的图都是残留网络,最初的时候正向边容量等于原图该边容量,反向边容量为 \(0\)

Q:找到了一条增广路后可行流流量要加多少?

A:所有边的容量的最小值(因为需要保证每一条边都满足流量小于等于容量)。

Q:怎么更新残留网络?

A:假设增广路的每一条边(也就是答案的增加量)的流量为 \(f\),那么正向边的容量减去 \(f\),反向边的容量加上 \(f\)(因为还能再增加的流量少了 \(f\),还能再减少的流量加了 \(f\))。

Q:怎么求一条边的反向边?

A:用邻接表比较方便。存图的时候可以将一对正反边存在相邻的位置,也就是 \((0,1),(2,3)\) 这样存。这样反向边的编号等于正向边的编号异或 \(1\)

Q:怎么把这一条增广路的路径全部存下来?

A:可以记录一个 \(pre_i\) 数组表示 \(i\) 这个点是从哪条边过来的,这样从 \(pre_t\) 开始一直遍历到 \(s\) 就是整条路径了。

\(\text{EK}\) 算法的时间复杂度为 \(O(nm^2)\),实际表现会快很多,大概可以解决规模在 \(500\)\(10000\) 的网络。

网络流之 \(\text{Dinic}\) 算法

模板题:P3376 【模板】网络最大流

\(\text{Dinic}\) 的总体思路和 \(\text{EK}\) 差不多,主要优化在于每一次不只是找了一条增广路,而是找了多条增广路(用 dfs 遍历),其实找的也不是原本意义上的增广路了,而是一条可行流(主要区别在于不是一条路径了,有可能一个点连出去多条边,但一定满足是可行流)。而由于图中有可能有环,为了避免一直死循环,所以我们引入一个分层图的思想。每个点的“层数”等于该点到源点的距离,每一次 dfs 遍历的时候都只能从一个点走到它下一层的点上。

dfs 的时候维护一个 \(limit_u\) 表示前面经过的所有边的容量的最小值(也就是前面所有边的流量最大是多少),且 dfs 的返回值为从这个点开始的可行流的最大流量是多少(没有增广路返回为 \(0\))。然后往后面遍历每一个邻点,并且计 \(flow\) 表示当前点开始的可行流的流量。那么每一次遍历 \(u\) 的邻点 \(v\)\(flow\) 需要加上 \(dfs(v)\)。且 \(v\) 点的 \(limit_v\) 应该设为 \(\min(c(u,v),limit_u-flow)\),因为加上从 \(v\) 点出发的可行流流量之后也应该不超过 \(limit_u\),并且从 \(v\) 点出发的可行流流量不能超过这条边的容量。

\(\text{Dinic}\) 还有一些很重要的优化方式:

  1. 废点优化

在残留网络中,如果从一个点出发已经走不到汇点 \(t\) 了,那么可以将这个点删除(因为现在已经走不到了之后肯定还是走不到)。

  1. 当前弧优化

假设我们用邻接表存图,那么对于一个 \(u\),每一次遍历邻边都是按照一定顺序从前到后遍历的。且每一条边能流过的流量都是有限的,如果想要遍历到下一条边首先需要满足上一条边的流量已经流满了(否则一定会按照顺序先流上一条边)。那么如果 \(u\) 一些邻边已经流满了,后面再遍历到这个点的时候就不用再去遍历这些邻边了。所以我们对于每一个点可以记录一个当前弧表示这个点的哪一条邻边还没有流满。遍历到这个点的时候直接从当前弧开始遍历即可。

  1. 流量限制优化

如果当前的 \(flow\)(从当前点开始的最大流量)已经大于 \(limit\)(前面点的最大流量)了,直接退出。因为不可能再增加边了,否则就不是一个可行流了。这个优化也是为了辅助当前弧优化。

\(\text{Dinic}\) 算法的时间复杂度为 \(O(n^2m)\),实际表现也会快很多,大概可以解决规模在 \(5000\)\(100000\) 的网络。

无源汇上下界可行流

给定一个无源点和汇点的流网络,每一条边有一个流量上限,还有一个流量下限。求出这个网络的一个可行流

这个问题显然不能直接做,因为没法处理流量下界的限制,于是我们考虑如何消除这个限制。我们还是可以引用通俗的办法,试着去建一个新图,使得新图只用考虑流量上界,且和原图的可行流一一对应。有一个很直观的转化,就是把每一条边的流量下限,实际流量,和流量上限全都减去流量下限,这样流量下限就为 \(0\) 了。

分析一下这样做对不对。首先是判断新图中的流量满不满足容量限制,这个是一定满足的,因为原图中是可行流(满足容量限制),现在将每条边的三个属性同时减去一个数,肯定还是满足条件的。再来看满不满足流量守恒,答案是不一定满足。因为对于每一个点 \(u\),它的入边的流量减少的值和它的出边的流量减少的值是不一定相同的(每一条边的流量下界不同,所以每一条边减去的值也不同)。那如何使它满足流量守恒呢?其实可以把差的流量补上去。具体来讲,设 \(c1_u,c2_u\) 分别表示 \(u\) 点的所有入边和出边的流量下限之和(也就是所有入边和出边分别减去的值),并且建立虚拟源点 \(S\) 和虚拟源点 \(T\)。那么 \(u\) 点相对于原来差的值为 \(c1_u-c2_u\)。如果这个值大于 \(0\) 的话,就从 \(S\) 连向 \(u\) 一条容量为 \(c1_u-c2_u\) 的边,否则从 \(u\)\(T\) 连一条容量为 \(c2_u-c1_u\) 的边,这样如果这条边流满了的话 \(u\) 点就满足流量守恒了。

所以我们按照上述建立新图。原图中的每一个可行流都对应了新图中源点和汇点的出边都流满的可行流,这其实就是新图的最大流!所以我们只需要在新图中找到最大流,如果最大流满足源点所有出边流满的话,那么一定对应着原图的一个可行流。否则原图不存在可行流。

有源汇上下界最大流

给定一个有源点和汇点的流网络,每一条边有一个流量上限,还有一个流量下限。求出这个网络的一个最大流

模板题:P5192 Zoj3229 Shoot the Bullet | 东方文花帖 |【模板】有源汇上下界最大流

首先考虑如何将一个有源汇的网络转化成一个无源汇的网络。会发现有源汇的网络唯一的区别就是源点 \(s\) 和汇点 \(t\) 可以不满足流量守恒。所以我们可以增加一条从 \(t\)\(s\) 的虚边,容量为 \(+\infty\),这样就变成无源汇了(因为可以通过这条虚边来使它满足流量守恒),并且对原问题没有影响。

这样就已经可以求出有源汇上下界可行流了。

接下来考虑如何把求一个可行流变为求一个最大流。一个结论是:还是按照找可行流的方式建立虚拟源点 \(S\) 和虚拟汇点 \(T\)。然后找到这个新图的 \(S\)\(T\) 的最大流(且源点必须是满流),对应到原图的一个可行流(到此为止都和无源汇上下界可行流一致)。然后再在这个新图上求出 \(s\)\(t\) 的最大流,并将这个最大流的流量值加到原来的可行流的流量上,最终值即为答案。

为什么这样做是正确的?先讲一种经典的错误的证明方式。

证明:因为我们最终找的是 \(s\)\(t\) 的最大流,所以最终残留网络中一定不存在增广路,所以是最大流。

驳论:这个论证的论点是正确的,但是论据是没有逻辑的。首先我们要清楚可行流,残留网络和增广路是有一致性的。什么意思?就是说可行流 \(f\) 是从 \(s\)\(t\) 的可行流,而残留网络是根据可行流 \(f\) 而定的,残留网络中的求的增广路也是从 \(s\)\(t\) 的增广路。而这道题中我们先求的是 \(S\)\(T\) 的最大流(残留网络),但是我们却在 \(S\)\(T\) 的残留网络中求 \(s\)\(t\) 的增广路,这里的逻辑是不正确的。

正确证明:考虑判断原图中的可行流是不是和残留网络中 \(s\)\(t\) 的可行流是一一对应。首先证明原图中的可行流是不是一定对应着一个残留网络中 \(s\)\(t\) 的可行流。我们将原图的可行流转化成新图中的一个最大流 \(f1\),那我们看一下这个对应过来的最大流和我们在代码里求的那个固定的最大流 \(f\) 有什么关系。会发现一个很神奇的性质,如果用 \(f1\) 减去 \(f\) 的话,\(S\)\(T\) 所连的边的流量都变成 \(0\)(因为两个最大流中 \(s\) 的所有出边和 \(t\) 的所有入边都一定流满了),这样 \(S\)\(T\) 一定是满足流量守恒的。反过来证明类似。这样就证明出来原图的最大流一定对应着残留网络中 \(s\)\(t\) 的最大流了,且最大流流量等于第一次 \(s\)\(t\) 的流量加上第二次 \(s\)\(t\) 的流量。但是我们会发现如果这个最大流不是满流的话就证明不了这个结论了,所以这个证明也依赖于本题的特殊性质,用在一般网络上就不行了。

那第一次的从 \(s\)\(t\) 的流量怎么算呢?其实就等于 \(t\)\(s\) 这条虚边的流量,因为整个无源汇的网络一定满足流量守恒。

注意最终在找 \(s\)\(t\) 的最大流的时候要把 \(t\)\(s\) 的虚边删掉,不然出现问题。

有源汇上下界最小流

给定一个有源点和汇点的流网络,每一条边有一个流量上限,还有一个流量下限。求出这个网络的一个最小流

和有源汇上下界最大流的做法基本一样,只不过最后不求 \(s\)\(t\) 的最大流了,而是求最小流。直接求最小流不好做,于是我们可以反过来求 \(t\)\(s\) 的最大流,这样这个流量的相反数就是 \(s\)\(t\) 的最小流了。

多源汇最大流

给定一个有多个源点和汇点的流网络,每一条边有一个容量,求这个网络的最大流

建立虚拟源点 \(S\) 和虚拟源点 \(T\),从 \(S\) 向图中的每一个源点连一条容量为 \(+\infty\) 的边,同理从图中每一个汇点向 \(T\) 连一条容量为 \(+\infty\) 的边。这样原图的最大流就转化为了 \(S\)\(T\) 的最大流。

最大流之关键边

一个网络的最大流的关键边是指如果将这条边的容量增大,会导致这个网络的最大流变大。

模板题:POJ 3204 Ikki's Story I - Road Reconstruction

如何求出所有关键边?我们先求出这个网络的最大流。考虑现在每一条边的流量,如果某一些边是没有流满的,那么这条边一定不是关键边。现在它的容量都还没有用完,那么不管加上多少都是没有用的。所以关键边一定是流满了的边。再考虑将这个最大流的残留网络建出来,显然是没有 \(s\)\(t\) 的增广路的。但是如果最大流想要变大,就必须出现增广路。又因为我们只能改变一条边的容量,所以假设这条边是 \(u \to v\),那么这条边还必须满足 \(s\) 能通过容量大于 \(0\) 的边走到 \(u\)\(v\) 能通过大于 \(0\) 的边走到 \(t\),这样才能满足将 \(u \to v\) 的容量变大过后出现增广路。

总结一下,关键边 \(u \to v\) 必须满足三个条件:

  1. 这条边流满了。2. \(s\) 能通过容量大于 \(0\) 的边走到 \(u\)。3. \(v\) 能通过大于 \(0\) 的边走到 \(t\)

怎么判断二三条件呢,可以分别从 \(s\)\(t\) 开始遍历一遍所有能够过容量大于 \(0\) 的边到达的点,遍历到的点就是满足条件的点。注意从 \(t\) 开始的遍历时,走的是反向边,但是判断容量的时候应该判断正向边。

最大流之判定类问题

给定一张无向图和一个 \(t\),需要在原图中找到 \(t\) 条互不相交的从 \(1\)\(n\) 的路径。最小化所有路径的边权的最大值。

模板题:P1674 [USACO05FEB] Secret Milking Machine G

因为本题是最小化一个最大值,所以考虑先二分答案。那么问题可以转化为判断是否有 \(t\) 条互不相交的从 \(1\)\(n\) 的路径使得边权最大值小于等于 \(mid\)。源点设为 \(1\),汇点设为 \(n\)。因为每一条边只能用一次,所以我们可以把每一条边的容量设为 \(1\)。注意边权大于 \(mid\) 的边不能用(因为边权最大值小于等于 \(mid\))。但是因为这是无向边,所以要建立两个方向的边。求出这个图的最大流,则这个最大流的流量代表的就是最多有多少条互不相交的从 \(1\)\(n\) 的路径。将这个值和 \(t\) 进行比较即可。但是有一个问题,题目说每条边只能走一次,但是我们却建了双向边,不会走两次吗?其实如果走了两次的话,可以转化为一次都不走,这样总流量不变,且还满足容量限制和流量守恒。

如何证明最大流的流量等于最大不相交路径数?因为源点流出了 \(t\) 条流量,那么相当于从源点走出去了 \(t\) 条边。因为每个点的流量守恒且流量最多为 \(1\)。所以通过这 \(t\) 条边的流量最终一定会通过不同的边流到汇点,于是就一定有 \(t\) 条不相交路径。

最大流之二分图最大匹配

求二分图的最大匹配数。

模板题:P3254 圆桌问题

如果用匈牙利算法来求的话时间复杂度是 \(O(nm)\) 的,用网络流可以优化到 \(O(\sqrt n m)\)。首先建立源点 \(s\) 和汇点 \(t\),因为每个点只能使用一次,所以从 \(s\) 向左部点连一条容量为 \(1\) 的边,从右部点向 \(t\) 连一条容量为 \(1\) 的边。对于左部点到右部点,如果这两个点之间在原图上有边的话,那么建一条容量为 \(1\) 的边。这个网络的最大流就是原图的最大匹配数。

证明:对于原图的一个匹配,如果一个左部点匹配了右部点,那么在网络中从 \(s\) 到对应左部点的边流 \(1\) 的流量。同理如果一个右部点匹配了左部点,那么在网络中从对应右部点到 \(t\) 的边流 \(1\) 的流量,中间的边如果两个端点点如果匹配了就流 \(1\) 的流量,这个流一定是可行流(满足容量限制和流量守恒),所以原图的一个可行匹配一定是一个可行流。对于一个可行流,将 \(s\) 到左部点和右部点到 \(t\) 的流量删掉,剩下的流量为 \(1\) 的边一定是原图的一个匹配。所以一个可行流一定是原图的一个可行匹配。所以可行流和可行匹配是一一对应的,于是得证。

网络流之拆点

求三分图的最大匹配数。

模板题:POJ 3281 Dining

我们可以先按照二分图最大匹配的建边方式来建边\(--\)源点连向左部点,左部点连向中部点,中部点连向右部点,右部点连向汇点。但是我们会发现这样建图是不对的,因为求出的方案中,中部点可能会被用多次(左部点连向它和它连向右部点的边的数量都有可能大于 \(1\))。这时就要引入一个新的技巧了,拆点

我们可以将中部的所有点拆为两个点(称之为拆点):入点和出点,且这两个点中间有一条边。这两个点就好比两扇门,入点是入口,出点是出口,中间的边是过道。我们可以把对进门和出门的人的限制转化为对过道中的人的限制。这样做有什么好处?好处在于一般求最大流的时候点是没有容量的,但是边是有容量的,这样做可以将对点的限制转化为对边的限制。对于这道题来说,我们只需要将入点到出点中间的边的容量设为 \(1\) 即可,这样就可以保证中间的一个点最多只会被用一次了。注意三分图的左部点,中部点和右部点是有顺序的,不能随便换。因为题目中一般会给出 \(A\)\(B\) 的关系,\(B\)\(C\) 的关系,那么只能让 \(B\) 来做中部点。

当然拆点也不只适用于这一个场景,当我们想要给点一个限制或者将点转化为边的时候,都可以用拆点这个技巧。

网络流之拆边

模板题:P4307 [JSOI2009] 球队收益 / 球队预算

如果一条边的费用或容量在不同情况下是不同的,且是单调递增或者递减的。那么我们可以把这条边所有可能的权值都分别建一条边。

最大流之最小路径覆盖问题

给定一张有向无环图。这张图的路径覆盖是指 \(k\) 条互不相交的路径(起点和终点任意,可以为单独的一个点)刚好覆盖整个点集。最小化 \(k\) 的大小。

模板题:P2764 最小路径覆盖问题

首先最坏情况下肯定是每个点作为一条路径,一共 \(n\) 条,现在我们需要尽可能减少路径条数。考虑把减少路径数量的过程转化为合并两个相邻的点的操作。但是每个点只能被连向它的点合并一次,再合并一次从它连出去的点(因为路径不能有分叉)。那么我们可以把一个点拆为两个点,分别表示连向它和从它连出去,变为一个二分图,对于原图的每一条边从左部点连向对应的右部点,容量为 \(1\)。这样每选择一条边就相当于合并了一次,所以求这个二分图的最大匹配即可。因为每个点最多匹配一次,所以一定保证每个点都只能最多被连向它的点合并一次,再合并一次从它连出去的点,符合题意。最终答案为 \(n-ans\)

哪如何求出具体每一条路径的方案呢?会发现如果一条边有流量的话,就说明将这一条边的两个端点合并了(即在同一条路径上),可以用并查集维护。

最小割

给定一个流网络,求出这个流网络的最小割以及原网络分成的两个集合 \(S\)\(T\)

模板题:P2944 [USACO09MAR] Earthquake Damage 2 G

根据最大流最小割定理可得,流网络的最小割等于最大流。所以求最小割等价于求最大流,用 \(\text{Dinic}\) 即可。但是这样求的是一个值,怎么求具体的分割方案呢?类似于证明最大流最小割定理(二)推(三)的方法,我们在增广完的残留网络中从 \(s\) 开始遍历,沿着容量大于 \(0\) 的边一直走,标记走过的所有点。这些所有被标记过的点(包括 \(s\))为一个点集 \(S\),剩下的点为另外一个点集 \(T\)。这一定是一个合法的割,因为 \(s\)\(t\) 一定不在同一个集合。这个割还一定满足所有从 \(S\)\(T\) 的边一定都是满流,从 \(T\)\(S\) 的边的流量全部为 \(0\),所以割的流量等于割的容量,所以这就是最小割。

那如果我们要指定点 \(u\) 在割中必须和源点在一个集合里面,怎么做呢?只需把 \(s\)\(u\) 的边的容量设为 \(+\infty\) 即可。因为最终找方案的时候是从 \(s\) 开始一直沿着残留网络中容量大于 \(0\) 的边走。又因为 \(s \to u\) 这条边的容量为 \(+\infty\),所以不管这条边流了多少,在残留网络中的容量一定大于 \(0\),所以 \(u\) 一定会被 \(s\) 遍历到。 其实在最小割中,如果我们想要某一些边不被选为最小割的割边,我们就可以把这条边的容量设为正无穷,这样最小割一定不会包括这条边了(当然前提是这条边为正向边)。

如果求的是割点的话可以把每个点拆为两个点,在这两个点中间连一条边,其它边的容量都设为 \(+\infty\)(因为割边只能为原来的点,也就是现在入点连向出点的边,不能是其它边)。这样新图的最小割的割边就可以对应到原来的割点了。

最小割之二者取一式问题

给定 \(n\) 个点,你可以将这 \(n\) 个点放入 \(A\)\(B\) 集合中。每个点有两个价值 \(a_i\)\(b_i\) 分别表示放入 \(A\) 和放入 \(B\) 的价值。还有 \(k\) 个组合,每个组合有多个点。这个组合也有两个价值 \(c_i\)\(d_i\),分别表示将这个组合的所有点都放入 \(A\) 和放入 \(B\) 的价值。求一种方案使得总价值最大。

模板题:P1361 小M的作物

经典的二者取一式问题。首先先不考虑组合的价值,从每个点向 \(s\) 连一条容量为 \(a_i\) 的边,向 \(t\) 连一条容量为 \(b_i\) 的边。这时我们会发现,最大价值就等于 \(\sum (a_i+b_i)\) 减去最小割。考虑如何计算组合的价值(先只考虑放到 \(A\) 集合的价值)。对于每一种组合,我们可以建立一个虚点表示这种组合,从这个点向 \(s\) 连一条容量为 \(c_i\) 的边。但是这个组合中只要有一个点在 \(B\) 集合,这条边就必须成为割边(因为需要减去)。所以我们可以再从这个虚点向组合内每一个点连一条容量为 \(+\infty\) 的边。只要组合中有一个点在 \(B\) 集合,因为正无穷的边不会成为正向割边,所以虚点也一定在 \(B\) 集合,这样从虚点连向 \(s\) 的边一定是割边,于是就解决了。

可能会有疑问:因为容量为正无穷的一定不是割边,那每个组合中的点不就都必须在一个集合中了吗?这与题意不符啊。其实不一定分在一个集合。因为割的容量只考虑正向边,所以如果反向边的容量为正无穷是不会影响割的容量的。所以我们可以让一些反向的割边的容量为正无穷,这样就同一组就不一定分到一个集合了

最小割之最大权闭合图

求出一个有向图(有点权,且点权可能为负)的最大权闭合图

模板题:P4174 [NOI2006] 最大获利

闭合图是指在一个有向图中的一个点集,满足这个点集中的所有点的出边所连接的点都是这个点集内部的点,不会有指向不是这个点集中的点的边。形象的说就是“肥水不流外人田”。而最大权闭合图指的是所有闭合图中点权之和最大的一个。

我们可以把这个问题转化为最小割模型。首先建立源点 \(s\) 和 汇点 \(t\),从 \(s\) 向所有点权为正的点连边,容量为这个点的点权。从所有点权为负的点向 \(t\) 连边,容量为点权的绝对值。原图中原本存在的边的容量设为 \(+\infty\)。我们定义一个简单割的概念(这个概念只在特定问题下有):所有割边的端点都包含 \(s\)\(t\) 的割(相当于没有中间的割边)。那如何求简单割的最小值呢,其实就等于最小割。因为最小割肯定为有限值(等于最大流),所以割边的容量不会为 \(+\infty\),也就是没有中间的边,所以就是简单割。

那现在需要证明原图的一个闭合图和流网络中的一个简单割是一一对应的关系。首先看原图的一个闭合图是不是能转化为流网络中的一个简单割。假如原图的闭合图的点集为 \(V\),那么我们把 \(S\) 设为 \(V\) 加上源点,其它点(包括汇点)为 \(T\)。这一定是一个简单割,因为闭合图满足没有向外的边,所以割边要么是从 \(s\)\(T\),要么是从 \(S\)\(t\),这满足简单割的定义。再来看流网络中的一个简单割是不是能转化为原图的一个闭合图。对于一个简单割 \([S,T]\),我们把假设点集 \(V\)\(S\) 减去源点。因为简单割满足只有包含 \(s\)\(t\) 的割边,所以 \(V\) 这个点集的出边都一定指向 \(V\) 中的点或 \(t\),但是指向 \(t\) 的边在原图中是不存在的,所以 \(V\) 是一个闭合图。

我们还需要求出一个闭合图的点权和(\(sum\))和它对应的简单割的容量(\(c[S,T]\))有什么数量关系。

假设简单割为 \([S,T]\)\(V\) 为点集。\(V1=S-{s},V2=T-{t}\),加 / 减号角标表示集合中的正数 / 负数。

\[sum=\sum_{v \in V1^{+}} (w_v)-\sum_{v \in V1^{-}} (-w_v) \]

\[c[S,T]=\sum_{v \in V2^{+}}(w_v)+\sum_{v \in V1^{-}}(-w_v) \]

这时我们会发现:

\[sum=\sum_{v \in V^{+}}(w_v)-c[S,T] \]

因为 \(\sum_{v \in V^{+}}(w_v)\) 是定值(所有点权大于 \(0\) 的点的点权和),所以只需求出最小割即可满足 \(sum\) 最大。

最小割之最大密度子图

求出一个无向图的最大权闭合图

模板题:UVA 1389 Hard Life

对于一个无向图(没有点权和边权,也可以理解为点权和边权都为 \(1\))来说,它的一个子图是指:一个边集和一个点集,其中边集中的边必须满足两个端点都是点集里的点。一个子图的密度是这个子图的边数除以这个子图的点数,也就是 \(\frac{|W|}{|V|}\)。顾名思义,最大密度子图就是密度最大的子图。

看到这种分数的形式,首先可以考虑 \(01\) 分数规划。我们可以二分一个 \(g\),那么问题变为了判断 \(\frac{|W|}{|V|}>g\) 是否有解,转化一下变为 \(|W|-g|V|>0\),我们的目标是去最大化左边式子值。再考虑一下最大密度子图的性质,我们会发现,如果已经选择了一个点集,那么边集一定要选满才是最优的,因为这样分子最大。也就是说选的子图一定是一个导出子图。那么对于一个点集 \(V\) 和边集 \(E\),我们尝试计算一下上述表达式的值,因为最小割只能求最小值,所以我们先将原式取反,这样求的就是最小值了。

\[g|V|-|W|=\sum_{v \in V}g-\sum_{e \in E}1 \]

如果我们还是按照最大权闭合图那样定义 \([S,T],V\) 的话,因为我们选的是一个导出子图,所以 \(V\) 的所有出边要么还是包含在点集 \(V\) 里,要么就是割边。所以一个导出子图中边的数量等于这个导出子图中(所有点的出边的数量之和(也就是所有点的度数和)减去割的数量)除以二。于是可以化简上式得:

\[g|V|-|W|=\sum_{v \in V}g-\frac{\sum_{v \in V}d_v-c[S,T]}{2} \]

\[g|V|-|W|=\frac{1}{2}\times (\sum_{v \in V}(2g-d_v)+c[S,T]) \]

后面的 \(c[S,T]\) 就是割的大小,但是前面的一项不好算,所以我们可以构造一种构造流网络的方式,把前面的一项也结合到割里面去。因为 \(\sum_{v \in V}(2g-d_v)\) 是对于点来说的,所以我们可以将点权看做是 \(2g-d_v\),转化到流网络里面就是从 \(v\) 向汇点连一条容量是 \(2g-d_v\) 的边。但是我们会发现一个问题:\(2g-d_v\) 可能为负数。所以我们可以将所有边的容量都增加一个偏移量 \(U\),并且增加源点到所有点的容量为 \(U\) 的边,这样容量就一定为正了。原图中的边的容量直接设为 \(1\) 即可。

那么我们需要证明最小割的大小和上式的大小是成正比的,设 \(\bar{V}\) 表示 \(V\) 在原图中的补集。

\[c[S,T]=\sum_{v \in \bar{V}}U+\sum_{v \in V}(U+2g-d_v)+\sum_{u \in V}\sum_{v \in \bar{V}}w(u,v) \]

\[c[S,T]=\sum_{v \in \bar{V}}U+\sum_{u \in V}((U+2g-d_u)+\sum_{v \in \bar{V}}w(u,v)) \]

\[c[S,T]=\sum_{v \in \bar{V}}U+\sum_{u \in V}((U+2g)-\sum_{v \in V}w(u,v)) \]

\[c[S,T]=U \times n+\sum_{u \in V}2g-\sum_{u \in V}\sum_{v \in V}w(u,v)) \]

\[c[S,T]=U \times n+2g|V|-2|E| \]

很容易发现,这个式子和 \(g|V|-|E|\) 是成正比的,具体来说:

\[g|V|-|E|=\frac{c[S,T]-U \times n}{2} \]

于是我们只需要求出最小割,即可求出原式了。通过看原式是否大于 \(0\) 来判断当前二分到的 \(g\) 是否合法。

拓展一:如果带边权的话怎么做。

这个比较简单,直接将原图中的边的容量设为该边的边权即可。

拓展二:如果带点权的话怎么做。

假设点 \(i\) 的点权为 \(p_i\),那么我们要求的式子变为了:

\[\frac{|W|+\sum_{v \in V}p_v}{|V|}>g \]

\[g|V|-|W|-\sum_{v \in V}p_v<0 \]

因为:

\[g|V|-|W|-\sum_{v \in V}p_v=\frac{1}{2}\times (\sum_{v \in V}(2g-2p_v-d_v)+c[S,T]) \]

观察这个式子和没有点权时的式子的区别,发现只有一个地方不一样:\((2g-d_v)\) 变为了 \((2g-2p_v-d_v)\)。所以我们可以把从每一个点连向 \(t\) 的边的容量从 \((2g-d_v)\) 变为 \((2g-2p_v-d_v)\) 即可。

最小割之二分图最小权点覆盖集

求出一个二分图的最小权点覆盖集

模板题:POJ 2125 Destroying The Graph

对于一个无向图来说,它的点覆盖集是一个点集,满足图中的每一条边的两个端点至少有一个包含在所选的点集里面。最小权点覆盖集指的就是点权之和最小的一个。

如果对于一个普通图的话,求最小权点覆盖集是一个 NP 完全问题。但是对于一个二分图来说,可以用网络流来做到一个比较优秀的时间复杂度。因为每个点都有点权,所以我们建立源点 \(s\) 和汇点 \(t\),从源点向每一个左部点连一条边,容量为该点的点权,同样从每个右部点向 \(t\) 连一条边,容量为该点的点权。对于二分图中两点之间的边,容量设为 \(+\infty\)(这样中间的这些边一定不是割边)。

还是引入简单割的概念:只有包含 \(s\)\(t\) 的割边的割。那么我们来看一下简单割和点覆盖集是不是一一对应的关系。先看简单割能不能对应到一个点覆盖集。因为只有包含 \(s\)\(t\) 的割边(\(s\) 到左部点的边和右部点到 \(t\) 的边),所以对于每一条割边,我们把这条边的不是 \(s\)\(t\) 的端点加入点集中。那这个点集是不是点覆盖集呢?一定是。考虑反证,如果不是的话,那么一定有一条边的两个端点都没被选,假设这两个点为 \(u,v\),也就是说 \(s \to u\)\(v \to t\) 都不是割边。那么 \(s\) 一定能通过 \(s \to u \to v \to t\) 走到 \(t\),这与简单割不符,所以得证。再看点覆盖集能不能对应到一个简单割,这里的点覆盖集指的是没有多余点的覆盖集,也就是说如果去掉一个点之后还是一个点覆盖集的话,那就把这个点去掉。我们把点覆盖集的所有点连向源点或者汇点的边设为割边(不能走),从 \(s\) 开始在原网络能遍历到的点属于 \(S\) 集合,剩下的属于 \(T\) 集合。因为图中一条边的两个端点至少有一个在点覆盖集中,所以从 \(s\) 不能走到 \(t\)(不能通过中间的边),所以这是一个割。且这是一个简单割,因为只有包含 \(s\)\(t\) 的割边。

那两者之间有什么数量关系?因为每一个点覆盖集的点都对应了一条割边。所以点覆盖集的点权和就等于简单割的容量。所以我们求最小权点覆盖集等价于求最小割。

那如何求出具体的最小权点覆盖集的方案呢,首先先求出最小割的方案。对于一条割边,我们把这条割边中不是 \(s\)\(t\) 的端点加入点集,最终的点集就是原图的最小权点覆盖集。

最小割之二分图最大权独立集

求出一个二分图的最大权独立集

模板题:P4474 王者之剑

一个无向图的独立集是一个点集,满足点集中的任意两个点之间都没有直接连边。最大权独立集则是点权之和最大的一个。独立集其实是和点覆盖集相对的一个概念。

性质:对于一张无向图,最大权独立集等于总点权和减去最小权点覆盖集。

证明:这个结论其实等价于每一个独立集的补集(点的补集)都是点覆盖集,每一个点覆盖集的补集都是独立集,因为这样如果点覆盖集最小的话那么独立集就一定最大了。首先考虑对于一个独立集,它的补集是不是一个点覆盖集?答案是肯定的。用反证法来证明,如果不是点覆盖集的话,那么一定有一条边的两个端点都不在补集中,也就是在独立集中。那这个就不是独立集了。所以它的补集是一个点覆盖集。再来考虑对于一个点覆盖集,它的补集是不是一个独立集。同样的证明方式,如果不是独立集的话,那么一定有一条边的两个端点都在补集中,也就是都不在点覆盖集中。那这个就不是点覆盖集了。所以它的补集是一个独立集。

所以我们想要求最大权独立集,只需要求出最小权点覆盖集,用总点权和减去它即可。

费用流之最小费用最大流

对于一张流网络来说,我们给每条边一个属性 \(w(u,v)\) 表示这条边的费用。那么对于一个可行流,这个可行流的费用为 \(\sum_{u,v \in V}f(u,v) \times w(u,v)\)最小费用最大流指的是所有最大流的方案中费用最小的一种。求出流网络的最小费用最大流。

模板题:P3381 【模板】最小费用最大流

我们可以把最初的 EK 算法中的 bfs 找增广路换成 spfa 找最短增广路,这样最终求出来的最大流的费用一定最小。

证明:首先假设我们找的最短增广路的流量为 \(f\),那么这一条增广路的费用为 \(f \times \sum w\),也就是流量乘上路径的长度。我们假设这种方案不是最优方案,那相当于还可以找到一个流量为 \(f\) 的增广路使得 \(f \times \sum w\) 更小。因为流量相同,所以后面这种方案的路径长度一定更短,这与前面的路径是最短路不符。所以前面找到的一定是最优的,也就是最小费用最大流。

Q:残留网络中的反向边的费用是多少呢?

A:反向边的费用设为正向边的费用的相反数。因为反向边的流量的意义是“退流”,那么费用的意义就是“退费”。

Q:这个算法一定能求出正确的最小费用最大流吗?

A:不一定。如果这个图不连通的话,那么有可能有一个连通块有流量(费用)但是我们遍历不到。

Q:最小费用最大流能用 \(\text{Dinic}\) 求吗?时间复杂度更优吗?

A:可以用 \(\text{Dinic}\) 求,但是时间复杂度差距不大。因为 \(\text{Dinic}\) 的本质是一次去寻找多条增广路,但是我们现在要求的是最短路,所以 \(\text{Dinic}\) 每一次还是只能找一条增广路。

Q:最大费用最大流怎么求?

A:只需要将 spfa 中的最短路改为最长路即可。

Q:如果原图中有负环的话这个算法还正确吗?

A:不正确。如果原图中有负环的话需要用消圈法去解决。

\(\text{EK}\) 求费用流的复杂度为 \(O(nmf)\)\(f\) 表示的是增广次数。

费用流之二分图最优匹配

给定一张二分图,每两个点之间的边有一个非负权值。求出这张二分图的一个匹配使得边权和最小。

模板题:P4014 分配问题

还是按照二分图的一般建图方式,建立虚拟源点和汇点。源点向左部点连边,容量为 \(1\)(因为一个左部点只能用来匹配右部点一次),费用为 \(0\)(因为一个点没有价值)。同理从右部点向 \(t\) 连边,容量为 \(1\)(因为一个右部点只能被左部点匹配一次),费用为 \(0\)(一个点没有价值)。对于中间的边,容量为 \(1\)(因为一条边只能包含在一个匹配中),费用为边的权值。因为边权为正,所以最优匹配一定是一个最大匹配,否则再选一条边匹配一定更优。所以最优匹配和网络中的最大流一一对应。然后跑一边最小费用最大流即可。

费用流之最大权不相交路径

给定一张有向图,每个点有点权,求出源点到汇点的总权值最大的 \(k\) 条不相交路径。

模板题:P4013 数字梯形问题

  • 情况一:\(k\) 条路径之间的边不相交。

只需把原图中每条边的容量设为 \(1\) 即可满足每条边不相交。考虑如何求出权值最大的路径。因为权值都在点上,所以我们可以用拆点的技巧。把每个点拆为入点和出点,从入点向出点连一条容量为 \(+\infty\)(可以多次经过这个点),费用为这个点的点权的边。这样最大权不相交路径就转化为了从源点到汇点的最大费用最大流。

  • 情况二:\(k\) 条路径之间的边和点都不相交。

把每个点的入点和出点之间的边的容量从 \(+\infty\) 变为 \(1\) 即可。

无源汇上下界最小费用可行流

求出一个无源汇网络可行流中费用最小的一个,其中每条边有容量上界和下界。

模板题:P3980 [NOI2008] 志愿者招募

按照无源汇上下界可行流的方式建出新图,那么新图的一个最大流(满流)就对应着原图中的一个可行流。那么我们只需要求出新图的最小费用最大流就对应到原图的最小费用可行流了。

网络流通用思维方式

网络流的最难点在于建模,而一般建模的思维方式有一下几个步骤:

  1. 先将原问题转化为一个流网络(注意流网络中的点在原问题中不一定是一个点或一个人,也有可能是一个事件或一个组合。流网络的一条边一般表示原问题的一个代价(费用)或限制(容量))。

  2. 看一下原问题的每一个可行解和流网络中的每一个可行流 / 割是否一一对应

  3. 计算原问题的可行解和流网络的可行流(流量或费用)/ 割(容量)之间的数量关系,并转化为最大流 / 最小割 / 最大最小费用流去求解。

对于一般的网络流问题,只要想出如何建图之后,就可以套用网络流模板(\(\text{EK},\text{Dinic}\))直接求解了。

posted @ 2023-12-19 09:15  Creeper_l  阅读(30)  评论(0编辑  收藏  举报