网络流相关

网络流

一个网络指一个有向图 \(G = (V, E)\),有两种特殊的节点:

  • 源点 \(S\)汇点 \(T\)

每条有向边 \((u, v) \in E\) 都有一个权值 \(c(u, v)\),被称为边的容量 ;显然当 \((u, v) \notin E\) 时,则 \(c(u, v) = 0\)。

一般用 \(f(u, v)\) 表示边 \((u, v)\) 上的流量 ,\(c(u, v) - f(u, v)\) 称为边的剩余容量

称一个流为可行流,需要满足:

  • 容量限制 :\(f(x, y) \le c(x, y)\)。

  • 流量守恒 :\(\sum\limits_{(u, x) \in E} f(u, x) = \sum\limits_{(x, v) \in E} f(x, v)\)(即流入 \(x\) 和从 \(x\) 流出的总流量是相等的)。

一般将 \(\sum\limits_{(S, x) \in E} f(S, x)\) 称为整个网络的流量,即从源点流出的所有流量之和。

最大流:从源点流向汇点的最大流量。

增广路:一条从源点到汇点且所有边的剩余容量都为正的路径。

最大流 EK 算法

一般求最大流的思想是:

  • 不断找增广路,更新答案,直到不存在增广路了为止。

为了防止卡死,我们还需要实现一个反悔 也称为退流的机制:

  • 即考虑对于有向边 \((u, v)\),建立一个反向边 \((v, u)\),初始容量为 \(0\)。

于是可以定义残余网 :由网络中所有节点和剩余容量大于 \(0\) 的边构成的子图,这里的边包括有向边和其反向边。

然后对于一条增广路(注意:增广路上可以有新增的反向边),设 \(mf\) 表示这条路径中容量的最小值;然后对于路径上的每条边,将其容量减去 \(mf\),其反向边的容量加上 \(mf\);此时整个网络的流将会增加 \(mf\)。

容易发现,对于一条有向边,它与其反向边的容量之和是等于初始容量的。

此时来说一下增广路的实际意义:

  • 若经过 \((u, v)\) 这条有向边,则相当于增加了 \(mf\) 的流量给 \(v\),所以到 \(v\) 的时候需要多流 \(mf\) 的流量;此时下一条边若为 \((v, p)\) 有向边,则给 \(p\) 多流了 \(mf\),继续往下迭代;否则若下一条边为有向边 \((p, v)\) 的反向边,表示退流操作,即将原先 \(p \to v\) 的流量减少 \(mf\),与 \(v\) 前面增加的流量抵消了。

即不断进行退流增流来维护流量守恒的同时增加这个增广

路的贡献。

普通的 EK 算法,就是通过不断 bfs 来找到任意一个增广路来更新最大流,时间复杂度理论上界为 \(O(nm^2)\),一般能处理节点数为 \(10^3 \sim 10^4\) 的网络。

为了快速处理正反边,使用链式向前星建图,正反两边从 \(2\) 开始编号,于是一个编号为 \(i\) 的边其反边编号是 \(i \oplus 1\)。

无源汇有上下界可行流

定义:

  • 一个 \(n\) 个点 \(m\) 条边的网络,对于第 \(i\) 条边 \((x, y)\),有限制为第 \(i\) 条边的流量 \(f(x, y) \in L(x, y), R(x, y)\),无源点汇点。

  • 一个可行流 是合法的当且仅当每条边流量的满足限制,且满足流量守恒

  • 一般的问题是判断是否存在可行流

对于一般的网络流是下界为 \(0\) 的特殊情况。

这个问题一眼较为困难,考虑使用调整法 解决,先初始钦定一组满足边限制的流,即每条边的流量直接取下界 \(L(x, y)\);这样可以发现每条边调整的范围在 \(0, R(x, y) - L(x, y)\) 之间,将下界降为了 \(0\)。

此时不一定满足流量守恒 ,考虑如何调整,对于点 \(u\),我们设 \(k = in(u) - out(u)\) 表示流入的总流量减去流出的总流量:

  • 若 \(k = 0\),该点满足流量守恒,不需要处理。

  • 若 \(k > 0\),则 \(u\) 至少需要多流出 \(k\) 的流量。

  • 否则 \(k < 0\),则 \(u\) 至少需要多流进 \(-k\) 的流量。

考虑如何满足上述的要求,容易想到进行朴素的网络流建图,对于原图的边 \((x, y)\),在新图上建立 \((x, y)\) 的容量为 \(R_i - L_i\) 的边(表示最多可以多流的流量):

  • 若 \(k > 0\),因为 \(u\) 需要多流出 \(k\) 的流量,即在新图上考虑从源点 \(S\) 给 \(u\) 一个 \(k\) 的流量,即建立 \((S, u)\) 容量为 \(k\) 的边。

  • 若 \(k < 0\),因为 \(u\) 需要多流入 \(-k\) 的流量,考虑将这 \(-k\) 的流量给 \(T\),即建立 \((u, T)\) 容量为 \(-k\) 的边。

我们称新图上和 \(S, T\) 相连的边为附加边

此时再新图上跑一次 \(S \to T\) 的最大流,此时显然新图上每个点都满足流量守恒 ,再此基础上,若所有附加边 全部满流,说明已经填上了之前需要多流的 \(|k|\)。

于是判断是否存在可行流只需要按照上述方式建新图,检测附加边的流量即可。

有源汇有上下界可行流

定义:

  • 一个 \(n\) 个点 \(m\) 条边的网络,对于第 \(i\) 条边 \((x, y)\),有限制为第 \(i\) 条边的流量 \(f(x, y) \in L(x, y), R(x, y)\),存在源点汇点 \(S, T\)。

  • 一个可行流 是合法的当且仅当每条边流量的满足限制,且除了源点汇点外满足流量守恒(且源点只向外流出,汇点只向内流入)。

  • 一般的问题是判断是否存在可行流

只是多了源点汇点,考虑转化成无有源汇有上下界可行流 ,即要使得 \(S, T\) 也满足流量守恒

于是容易想到建立 \((T, S)\) 流量限制为 \(0, +\\inf\) 的边,因为此时无论 \(S \to T\) 的流量 \(flow\) 是什么,只需要调整这条边的流量为 \(flow\) 就可以使得 \(S, T\) 流量守恒。

于是建立 \((T, S)\) 流量限制为 \(0, +\\inf\) 的边后跑一次无源汇有上下界可行流即可。

最大流类似,在残余网络上再跑一下最大流即可。

yny の 神 秘 优 化

本质上是按值域分块加边,把相近流量的边放在一起跑最大流:

cpp 复制代码
	inline long long dinic () {
		sort (Tmp.begin(), Tmp.end());
		long long Ans = 0;
		for (int i = 1e9, j = 0; j < (int) Tmp.size(); i /= 20) {
			while (Tmp[j].w >= i && j < (int) Tmp.size()) add_edge (j), ++ j;
			Ans += Solve ();
		}
		return Ans;
	}

这样可以卡的很快,但是在动态加边相关时没有用。

Simplex

考虑网络流的线性规划形式定义,然后使用网络单纯形法解决,复杂度是指数的,但是特别快。

最大流最小割定理

一个网络中 最大流流量 = 最小割容量。

一些 trick:

  • 强制一条边不能断的时候考虑钦定其流量为 \(+\infty\)。

P4313 文理分科

考虑没有相邻贡献的时候怎么建模?本质上是二选 \(1\) 模型,对于一个点,要么是文要么是理科,考虑:

  • \(S \to i\):流量为选文科的贡献。

  • \(i \to T\):流量为选理科的贡献。

显然此时的最小割剩下的方案就算选择的方案。

加上限制时呢?我们钦定答案是最小割,那么如果要算上 \((i, j)\) 四周学文的贡献的话,那么在最终的时候这 \(5\) 个人要在同一个连通块里;于是考虑建立新点 \((i, j)'\),先源点向他建流量为贡献的边,然后它向相邻的五个人连接 \(+\infty\) 的边表示不会断掉,此时无论怎么断边,这 \(5\) 个点都在一个连通块内,且只要这 \(5\) 个点中有一个断掉了和源点的边,那么 \(S\) 走新点再走这个往右边连的点就可以到达 \(T\),那么 \(S\) 到新点的边一定会断。

右边同理;最后用总的贡献减去最小割即可。

link

P3227 HNOI2013 切糕

依旧先不考虑限制,依旧考虑钦定答案是割。

考虑点转边,将 \((i, j, k)\) 的点权放在 \((i, j, k) \to (i, j, k + 1)\) 上,最后是放在到汇点 \(T\) 的边上;然后对于每条链,初始 \(S\) 向链顶 \((i, j, 1)\) 连 \(+\infty\) 的边表示不会断开;此时的最小割就是每条链上选一个 \(f(x, y)\) 断开的权值之和,是正确的。

考虑 \(|f(x, y) - f(x', y')| \le D\) 这个限制,显然只需要考虑 \(f(x, y) - f(x', y') \le D\) 即可,因为如果 \(f(x, y) - f(x', y') < -D\),那么 \(f(x', y') - f(x, y) > D\),也不满足前面那个限制。

如何对 \(f(x, y) - f(x', y') \le D\) 在图上加上限制?设限制断开了 \((x, y, k) \to (x, y, k + 1)\) 的边,那么在 \((x', y')\) 中断的边应该 \(f(x', y') \ge k - D\),于是考虑添加 \((x', y', k - D) \to (x, y, k)\) 的 \(+\infty\) 边,此时若断的边 \(< k - D\),那么 \(S\) 存在一个走 \((x, y)\) 链然后通过中转边到 \((x', y', k - D)\) 后到达 \(T\) 的路,不合法,于是满足限制了。

直接跑最小割即可。

link

等价流树

用于快速求任意两点之间的最大流。

注意!!!这不是最小割树,最小割树的性质更强:

  • 树上两点断边后对应的两个连通块恰是断的边两端点在原图上的一种最小割。

构造方式如下,考虑分治形式的构造:

  • 设当前点集是 \(S\),任意取出其中的两个点 \(u, v\)。

  • 原图 中跑出 \(u, v\) 的最小割,然后将 \(S\) 划分成了左右两个集合 \(L, R\)。

  • 建边 \((u, v)\),权值是最小割的值,然后递归到 \(L, R\) 分别再去建树。

考虑等价流树的性质,原图任意两点最小割容量等于树上对应两点路径最小值:

  • 证明一下,显然只需要证明 \(a \to b \to c\) 的情况就可以推广出去。

  • 钦定 \(w(a, b) = k_1, w(b, c) = k_2\) 且 \(k_1 < k_2\)。

  • 显然 \(w(a, c) \ge k_1\)(因为至少存在着 \(a \to b \to c\) 的 \(k_1\) 流)。

  • 若 \(w(a, c) > k_1\),说明存在着 \(a \to c\) 但是不经过 \(b\) 的增广路,而在 \(a \to b \to c\) 流中,显然还存在着 \(c \to b\) 的增广路,拼接一下就出现了 \(a \to c \to b\) 的增广路,于是不合法。

  • 则 \(w(a, c) = k_1\)。

需要跑 \(O(n)\) 次最小割,时间复杂度大概是 \(O(n^4)\)。

黑白染色

在 \(1 \times 2\) 放置或者一些性质的网格图中可以使用。

P7231 COCI 2015/2016 #3 DOMINO

将网格黑白染色后,显然覆盖了一黑一白,且由于不能重叠,考虑 \(S\) 向黑点建流量为 \(1\) 的费用为 \(w_{i, j}\),白点向 \(T\) 建,同理。

然后每个黑向四周的白建流量为 \(1\) 的免费边;此时跑最大费用最大流即可。

link

P4701 粘骨牌

首先黑白染色,然后你会发现空的格子一定是黑子。

考虑一下移动的限制,因为一个 \(1 \times 2\) 骨牌一定是一黑一白,所以移动的过后,一定是一个骨牌的黑色位置变成了之前空的格子,且这个骨牌盖住的白色格子是固定的;于是移动骨牌,可以看作是将空的位置交换到相邻可交换的黑点上。

于是可以先建一个黑点的图,表示所有的移动操作,然后考虑那些特殊位置,不能漏出来等价于 \(s\) 到它没有路径;于是考虑这样建图,以初始空位为源点 \(s\),建边流量为该骨牌的代价,对于特殊位置黑点,向汇点建容量为 \(+\infty\) 的边表示不能割掉;此时的最小割就是最小的代价断开 \(s\) 到那些特殊点路径的方案。

直接跑 dinic 即可,时间复杂度为 \(O(nm)\)。

link

出入度平衡

当出入度平衡时,可以看作是流量在环上流,即拆成入点出点去做。

P3965 TJOI2013 循环格

首先显然每个点出度为 \(1\),那么可以推出所有循环间两两没有交集,不然交集那里会出现出度为 \(2\) 的矛盾。

所以图由若干个互不相交的环构成,那么所有点入度也为 \(1\),且这也是充要条件。

为了确保出入度平衡,将每个点拆为左右两个点:

  • 初始源点向左部点建流量为 \(1\) 费用为 \(0\) 的边,右部点向汇点建立流量为 \(1\) 费用为 \(0\) 的边(意思是从这个点出去的流量"出度"最后一定会走一个循环回来"入度")。

  • 对于这个点本来指向的边,直接左部点向这个指向的点的右部点建立流量为 \(1\) 费用为 \(0\)。

  • 对于其它三个没指向的边,建立流量为 \(1\) 费用为 \(1\) 的边。

显然此时最大流为 \(n\),一定能跑满(因为一定存在解),那么跑最小费用最大流就行了。

时间复杂度为 \(O((rc)^3)\)。

link