网络流

【什么是网络流】

一张带权图,给定了一个源点(起点)和一个汇点(终点)。

每个点比作一个中转站,源点比作一个水源,汇点比作一个洞。

每条边比作一条管道,边权比作上限。


现在要把水从源点输送到汇点,水经过若干中转站和管道到达汇点。

但是,每条管道单位时间内输送的水不能达到这条管道的上限(权)。

每个中转点所到达的水可以分流进各个管道里。

某种方案把水流到汇点的量,称作这种方案的流量。


网络流处理有关于流量的问题。

【最大流问题】

我们想要让最多的水可以流到汇点。

那么,最多有多少水可以流到汇点呢?

网络最大流算法负责处理这个问题。


【一个原始的想法】

我们的想法:能流的话,就流。

从这个图里随便找一条源点到汇点的路(增广路:一条权值都大于 0 的从源点到汇点的路径)。

这条路上的边的最小权记为 a

a 单位的水沿着这条路流到汇点。

经过的所有边权,都减去 a,表示它最多能输送的水又少了 a

如果一条边的边权为 0,就相当于没有了。(饱和了,不能通)

【这个想法的反例】

这个图的最大流很明显是上下分两条。但如果我们不幸搜到了中间岔开的一条,就会 WA。

而下面找到的一条路有可能会阻断上下两条。

所以,这个想法一旦选定了一条本不该选的边,就无可挽回了。


【Ford_Fulkerson】

上面说到,这个想法挂掉的原因在于不能选不该选的边。

那么,我们可以考虑让我们可以 “反悔”。

而这,就是 Ford_Fulkerson 算法思想,以下简称 FF算法。

(因为只给了理论没给程序,只能是思想而不是算法)

【FF算法】

考虑每条边再建一条反向的边。

开始时,每条反向边的边权均为 0 。

反向边的意义是:可以反悔的额度。

比如,还是这个图。

把反向边建出来,并加上权。

假如我们走了这条横跨两大陆的边,有几条黑边输送了 1 的水,要减 1.

与此同时,这些边的反向边要加 1,即可以反悔的额度加 1 了.

于是图变成这样:

我们惊奇地发现,如果加了反向边,还能找到一条路:

如果走了这条路,我们横跨大陆的错误就纠正了。

如何翻译 “走了这条路” ?

当你走了一条反向边,相当于把来到这里的水又倒了一些出来。

这些水 “反悔” 了,换了一条路,再走一遍。

【具体实现】

我们知道了整个算法的流程,但其中还有一个问题。

我们一直在说:随便找一条路,如何找呢 ?

【直接做:EK】

就按照 FF算法 说的,我们就每次找一条增广路,然后流过去。

也就是每次从源点搜索一条到汇点的路径,然后流。

这种算法就叫做 EK(Edmonds-Karp),复杂度 O(n2m)

【图分层:Dinic】

我们进行一个优化:先从源点 BFS,只经过剩余容量 >0 的边,记录每个点的深度(距离)。

然后找增广路时,只走那些通向下一层的边。

【当前弧优化】

非常重要!

【有上下界的网络流】

【无源汇可行流】

建立超源点 S 和超源点 T。暂时只看每条边的下界,看每个点如果每条边都卡着下界,入度和出度比是多了还是少了。少了,就连一条到 T 的边,容量为少了多少;否则 S 连一条到这个点,容量为多了多少。

ST 跑最大流,判断所有 S 连出去的边是否都满流,如果不满流就不可行。

【有源汇可行流】

在上面图的基础上,在原来的 S,T 之间连一条 TS 的容量为 + 的边,然后跑 ST 最大流,判断是否满流。

(这个时候我们找到了一个可行流,且这个可行流就是此时 TS 这条边的流量)

(想知道 TS 的流量,可以通过遍历 T 的所有出边,找到 TS 的边,然后通过 rev 看反边)

【有源汇最大流】

上面的图跑完最大流得到残余网络,在这个残余网络上先删掉 TS+ 边后求 ST 的最大流,这个流加上上面可行流的流量就是最大流。(不用管 S,T,因为跑 S,T 都不会用到)

注1:删边 遍历出边,把 TS+ 边容量变成 0,同理找到 ST 对应反边容量也变成 0

注2:具体代码实现,删边可以直接调用 e[s],e[t] 的最后一个元素,因为 + 边是最后加上去的。

※ 注3:也可以不删边直接在残余网络上求 ST 的最大流。因为 TS+ 边的反边容量就刚好是第一轮最大流的流量。所以直接求 ST 最大流刚好会包含这条边。

【有源汇最小流】

也是残余网络删掉 TS 的边,但是跑 TS 的最大流,然后可行流减去这个最大流。

【费用流】

一般先保证最大流,再保证最小费用。

每条边每流一单位的流量,就要付一份这条边对应的钱。

先抛弃 Dinic,回归 FF 算法。

但是这次我们每次找增广路,用最短路算法找到一条费用最小的增广路,然后增广。

注意带费用的边的反边,费用就应该是负数了,因为反边代表的是反悔,反悔就要把费用吐出来。

复杂度:O(nmf),其中 f 等于图的最大流。

【正确性】

首先根据 FF 算法,只要是找增广路,就一定是对的。

但是是否每次找单个最小,就能得到总体最小?

是。(因为 FF 算法的反边是保证了一切反悔的可能性

【有源汇上下界最小费用最大流】

注意建图反边费用是负数!

注:所有额外边的费用都是 0

类比有源汇最大流,我们建了图后先跑一遍 ST 最小费用最大流,设这一次得到流量 f1,费用 c1

然后(不删边)再跑 ST 的最小费用最大流,设这一次得到流量 f2,费用 c2

则总共最大流量是 f2,最小费用是 c1+c2注意这里的费用不能直接取 c2,因为这里的费用不能直接用 + 的边做巧合。

【题目】

Telecowmunication 奶牛的电信

这题是割点,不是割边。那怎么做?

把每个点拆成入点和出点。入点向出点连一条容量为删除这个点代价的边。

然后可以通信的点之间,入点向出点连 + 的边。

于是就可以最小割了。

蜥蜴

最少留下 = 总 - 最多离开。

也把每一个格子分成入点和出点,对于每个格子只能经过多少只蜥蜴,其入点就向出点连多少容量的边。

互相能跳跃的格子,连容量 + 的边。此时最大流就是最多离开。

除此之外,怎么分配初始蜥蜴?我们可以建立超源点 SS 向所有有蜥蜴的格子连边。

同时建立超汇点 T,所有能跳出边界的出点都向 T 连边。

这题里面,我们认为格子的限制只在格子内部处理,格子之间是可以无限跳跃的。同时:我们认为蜥蜴不是一开始就在格子上,而是从一个位置 S 跳到初始格子上。

士兵占领

这题王老师的 std 写错了,把行和列的结点建到一起去了。

解法:

把士兵的分配看作都从源点出发,流到每个行,然后从每个行流到每个列上面去。

对行的限制体现在 srow 上,对列的限制体现在 colt 上,对格子障碍物的限制体现在 rowcol 上。用上下界网络流做。

具体而言:设第 i 行有 x 个格子可以放,则 s 向行 i 代表结点连一条容量 [l[i],x] 的边。设第 j 列有 x 个格子可以放,则列 i 代表结点向 t 连一条容量 [c[i],x] 的边。

然后如果 (i,j) 可以放士兵,则行 i 代表结点向列 j 代表结点连一条 [0,1] 的边。

然后求有源汇上下界最小流

圆桌问题

构造一个图:左边 n 个点,右边 m 个点,代表单位和桌子。

s 向左边每个点连边,容量 ri;右边每个点向 t 连边,容量 ci;左边每个点向右边每个点连边,容量 1

跑最大流,看看是否等于总人数。

如何找方案:循环左边每个点,再循环到右边的边,看看容量是否为 0

星际转移问题

之前 ZR 模拟做过类似的。

把地月看作 n+1,n+2,洪水填充判断是否有解。

拆点,每个点拆成 t 个点表示在不同的时间到这个点的状态。

初始源点向地球连 + 的边,表示允许任意多人到地球。求最短时间就是看第一个时间点,到达月球的人数达到 k

枚举 i=1+,然后枚举每艘太空船,找到它第 i 时刻所在位置,然后从 i 时刻位置向 i+1 时刻所在位置连容量 hx 的边。i 时刻的月球向汇点连 + 边。

加了新边之后跑最大流,把最大流加入目前的人数中,判断是否达到 k 人。如果是,就输出答案;不是,进入下一轮。

植物大战僵尸

神奇的建模。

先拓扑排序找出所有环和环的后继。这些一定是不会被吃的。

如果保护者指向被保护者,答案就是在剩下的点之间求最大权闭合子图。

(闭合子图:选一些点,使得如果 u 被选,则 u 的所有前驱都要选)

建模:建立超源超汇,原来保护关系的边都方向取反后变成 + 的边。

然后,若点 u 权值为正,Su,容量 au;否则 uT,容量 au

去掉拓扑排序后,所有收益为正的植物的收益之和 减去 最小割即答案。

拍照

也是最大权闭合子图。

m 个拍照事件做出 m 个点,n 个人做出 n 个点。

类比上面,每个人都保护了一些拍照事件。

海拔

观察:最终每个点的高度要么是 0,要么是 1。且最后的花费就是所有 01 的边的人流量。

观察:最后的图中,0,1 各形成一个连通块。

所以我们的问题:分成两个连通块,使得联通它们的边边权和最小。

直接最小割,但是发现还要优化。

对偶图!

对偶图是一种平面图最小割的优化方法。可以把最小割转化为最短路。可以上网搜。

CF704D

思路和蜥蜴一样,每个点的颜色视作先从超级源点流到每个 x 坐标上,再从 x 坐标流到 y 坐标上。然后就变成上下界网络流。

点要离散化,但是不能用 map,因为点可能重复.

餐巾计划问题

补充题意:初始没有餐巾;最后一天过了,餐巾是不是全部干净都行。

把每一天看成节点,餐巾的使用视作在节点之间流动。

具体而言,建立 2N 个点。每一天对应两个点,分别表示在这一天内干净的餐巾和脏的餐巾。

(以下没说费用都是 0

如何连边?首先,干净点 A 向干净点 A+ 的边,表示这天可以选择任意数量餐巾不用;脏点 A 向脏点 A+ 的边,表示这天可以选择任意数量餐巾不洗。

s1 连边,容量 +,费用 p,表示买餐巾。

ii 连边,容量 [r[i],r[i]],表示第 i 天会产生 r[i] 个脏餐巾。

ii+m 连边,容量 +,费用 f,表示快洗;

ii+n 连边,容量 +,费用 s,表示慢洗。

nnt 连边,容量 +

跑上下界最小费用流即可。

深海机器人问题

难点在于怎么处理每个生物标本只能被采摘一次。

首先生物标本是在点上的,对点的限制不好直接在图上体现。我们用一个经典 trick: 入点出点。

然后对于一个生物标本,我们从入点到出点连一条容量 1 的边,费用是生物标本的价值。

另外每个入点到出点,都连一条容量无穷,费用 0 的边。

跑最大费用最大流。

志愿者招募

我们把问题看作我们一开始有无限个志愿者。题目的“雇佣”就是让一些志愿者开始工作。设置 n+1 天,每一天抽象为一个结点,志愿者视作随着时间(天数)流动。

假如第 i 天需要 pi 人,则从 i 天向第 i+1 天连一条容量为 infpi 费用 0 的边,表示第 i 天最多有 infpi 人休息。

一类志愿者可以从 si 做到 ti 天,则从 siti+1 天连容量 + 的边,费用 ci

然后超源点 s 向第一天连容量 + 费用 0 的边,第 n+1 天向超汇点 t 也连同样的边。

这么跑最小费用最大流:

首先人数有 inf 个,最终也必须剩下 inf 个人(总流量必须是 inf)。为了最小费用,就会使用尽可能小的费用把 inf 个志愿者送到第 n+1 天,符合要求。

最大密度子图

参考

posted @   FLY_lai  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示