最大流简陋小记
posted on 2023-11-14 11:45:13 | under 笔记 | source
起因是某次模拟考出现二分图最大匹配,但是故意卡掉匈牙利只能用网络流,于是快速学了下。
超级简陋,之后或许会重写?
基本概念
想象一座城市的水网:
- 网络:水网。
- 源点 \(s\):有源源不断地水,相当于水厂。
- 汇点 \(t\):所有水最终汇入此处,相当于你家。
- 边:一条有向边,也可称弧。
- 容量 \(e_c\):水管每单位时间可经过的水的上界。
- 流量 \(e_f\):水管每单位时间内可经过的水。之后会用函数 \(f\) 的形式描述。
- 残留容量 \(e_r\):\(e_r=e_c-e_f\),水管还可继续流经的水量。
- 容量网络:边带容量的网络。类比有流量 / 残量网络。
- 网络的流量:\(\sum f(s,x)\) 或 \(\sum f(x,t)\)。你家总共收到的水。
流量的函数表示 / 性质
- 容量限制:\(e_f\le e_c\)。
- 流量守恒:\(\sum f(u,v)=0\),也可写为 \(\sum f(x,u) = \sum f(u,y)\)。有多少水流进来,就有多少水流出去。
- 斜对称性:\(f(u,v) = -f(v,u)\),比较难理解但是很重要。
最大流
求如何分配水流,使得网络的流量最大?我们将这样分配下的流量网络称作最大流网络。
增广路定理
- 增广路:在残量网络上一条从 \(s\) 到 \(t\) 的路径,满足边的残量均 \(>0\)。
- 增广路定理:该网络是最大流网络,当且仅当不存在增广路。
简单理解为:否则可以走这条增广路使得流量增加。
EK 算法
一种容易想到的思路是:建出残量网络,然后不断走增广路。
该算法流程如下:
-
初始化残量网络:\(r(u,v)=c(u,v),r(v,u)=0\)。
-
\(\rm bfs\) 找到最短增广路。
-
设增广路上最小残量是 \(minr\),则对其路上的所有 \(e(u,v)\) 都:\(r(u,v)-minr\),为了满足斜对称性对其反边 \(r(v,u)+minr\)。答案增加 \(minr\)。
-
重复 \(2,3\) 直到不存在增广路。
比较难理解的是反边(因为增广路可以由反边构成!),而且对边操作后其反边的残量还会增加,比较玄幻。
可以理解为正边的反悔标记。每次对 \((v,u)+minr\),就等于撤销 \((u,v)\) 上 \(minr\) 单位流量,并转移到增广路上使得答案增加.
而对于 \((v,u)-minr\) 的操作,建议看图手模下。大概思路:撤回曾经那次增广路操作 \(minr\) 容量,让它走旧路经前半和新路径后半到达 \(t\),并使得多出 \(minr\) 残量(相当于答案不变的情况下还能多出残量)。可以让 \(minr\) 流量走新路径前半和旧路径后半到达 \(t\)。总计 \(ans+minr\)。
dinic 算法
发现 \(\rm EK\) 算法每次只能更新一条增广路,能否同时更新多条呢?
\(\rm dinic\) 算法就实现了该思路,具体如下:
-
用 \(\rm bfs\) 求出原图的最短增广路,并根据访问次序标上层级(建分层图)。
-
用 \(\rm dfs\) 在分层图上同时更新多条增广路。
-
重复 \(1,2\) 知道不存在增广路。
关于第二步,具体如下:\(\rm dfs\) 过程中同时下传 \(sum\) 表示 \(s\to u\) 的增广路上最小边权,并在结束时返回 \(s\to u\to t\) 的所有增广路可更新的流总和 \(res\)。令下一层 \(v\) 的返回值为 \(k\),则可以更新增广路的 \(s\to u\) 部分的残量,于是有 \(sum-k\),同时 \(res+k\)。
不加优化复杂度错误,先说 当前弧优化:对于每个 \(u\),若 \(v_1...v_p\) 都被遍历了,则 \(s\to u\to v_j\to t\) 的所有增广路都被流满了(存在残量为 \(0\) 的边),因此不需再访问。可以用 \(now_u\) 记录下次要访问的边,不断推进即可。
还有一些剪枝,具体见代码。
最小割
- 割:是指有向图一边集,使得删去后 \(s\to t\) 不连通。
- 最小割:边权和最小的割。
首先有个最大流 \(=\) 最小割的定理。
理解:显然所有流都经过最小割,否则不符合定义,故最小割 \(\ge\) 最大流;再考虑最大流的最终局面,会存在一些满流边,显然最大流是从这些边得来的(瓶颈),那么它们必须构成割,否则仍存在增广路,故最小割 \(\le\) 最大流。综上定理得证。
关于最小割的方案输出:不难发现 \(s\to\) 最小割的流必定 \(>0\),而最小割上的边均为满流边。具体的,可以用 \(\rm bfs/dfs\) 从源点开始走残量为正的边,并标记所到的点。这里不能直接找残量为 \(0\) 的边的原因是避免重复,满流边并不总是处于最小割,但最小割一定是满流边。
一条边的起点被标记而终点未标记,则说明其属于最小割。
(注意去除反边)

浙公网安备 33010602011771号