洛谷 P3376:[模板] 网络最大流 ← Dinic 算法
【题目来源】
【题目描述】
如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。
【输入格式】
第一行包含四个正整数 n,m,s,t,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来 m 行每行包含三个正整数 ui,vi,wi,表示第 i 条有向边从 ui 出发,到达 vi,边权为 wi(即该边最大流量为 wi)。
【输出格式】
一行,包含一个正整数,即为该网络的最大流。
【输入样例】
4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 30
【输出样例】
50
【数据范围】
对于 30% 的数据,保证 n≤10,m≤25。
对于 100% 的数据,保证 1≤n≤200,1≤m≤5000,0≤w<2^31。
【算法分析】
● Dinic 算法被认为是网络流问题的“瑞士军刀”。在算法竞赛和面试中,掌握了 Dinic 算法就解决了 90% 的最大流问题。
● 网络流常用示意图()
在残量网络中找可增广路;
在实流网络中沿可增广路增流,在残量网络中沿可增广路减流。

增广路定理:设 flow 是网络 G 的一个可行流,如果不存在从源点 s 到汇点 t 关于 flow 的可增广路p,则 flow 是 G 的一个最大流。
● 残量网络(Residual Network)是网络流算法的核心概念。它不是独立构建的数据结构,而是基于原网络和当前流量动态计算出的“可用容量”的表示。
对于原网络 G=(V,E) 中的每条边 (u,v),其容量为 c(u,v),当前流量为 f(u,v)。残量网络包含两类边:
(1)正向边:剩余容量 c(u,v)−f(u,v)
(2)反向边:剩余容量 f(u,v)
● 利用“^1”运算表示反向边
由于网络流是有向有权图,因此可以选择链式前向星()存图。对一个数连续执行两次“^1”运算后,便会得到自身。这恰好与网络流中“反向边的反向边等于自身”不谋而合。因此,在网络流的算法实现中,我们可以利用“^1”运算来表示反向边。
● Dinic 算法中不需要显式构建完整的残量网络,而是通过修改边的容量来隐式维护。
● Dinic 不是简单的 DFS,而是“BFS 分层 + DFS 多路增广”的完美结合。其核心流程如下:
(1)BFS 构建分层图:从源点出发,计算每个节点到源点的最短距离(边数),形成“层次”。在残量网络中,规定只能从低层走向高层(d[v] = d[u] + 1),这有效避免了 DFS 在环里绕圈子。
(2)DFS 多路增广:在分层图上进行 DFS,一次性找出当前层次限制下所有可能的增广路,并更新流量。
(3)重复:当 BFS 无法到达汇点时,算法结束。
● 在 Dinic 算法中,用 STL 的 std::queue 写 BFS 层级图构建,确实很容易在性能敏感的大规模图(特别是稠密图、多次 BFS)中成为性能瓶颈,甚至导致 TLE。
【算法代码】
(1)本题代码中,dinic() 函数的返回值为 long long 型。
(2)由于 dinic() 函数需要建反向边,所以代码中的边数,至少需要设为题目陈述中边数的两倍。
(3)f[i] 表示第 i 条边的「剩余容量」。不是总流量,不是已用流量,是还能流多少!初始时,f[i] = 边的容量。流完后,f[i] 减少,f[i^1] 增加(反悔用)。
【参考文献】

浙公网安备 33010602011771号