网络流
【什么是网络流】
一张带权图,给定了一个源点(起点)和一个汇点(终点)。
每个点比作一个中转站,源点比作一个水源,汇点比作一个洞。
每条边比作一条管道,边权比作上限。
现在要把水从源点输送到汇点,水经过若干中转站和管道到达汇点。
但是,每条管道单位时间内输送的水不能达到这条管道的上限(权)。
每个中转点所到达的水可以分流进各个管道里。
某种方案把水流到汇点的量,称作这种方案的流量。
网络流处理有关于流量的问题。
【最大流问题】
我们想要让最多的水可以流到汇点。
那么,最多有多少水可以流到汇点呢?
网络最大流算法负责处理这个问题。
【一个原始的想法】
我们的想法:能流的话,就流。
从这个图里随便找一条源点到汇点的路(增广路:一条权值都大于
这条路上的边的最小权记为
把
经过的所有边权,都减去
如果一条边的边权为
【这个想法的反例】
这个图的最大流很明显是上下分两条。但如果我们不幸搜到了中间岔开的一条,就会 WA。
而下面找到的一条路有可能会阻断上下两条。
所以,这个想法一旦选定了一条本不该选的边,就无可挽回了。
【Ford_Fulkerson】
上面说到,这个想法挂掉的原因在于不能选不该选的边。
那么,我们可以考虑让我们可以 “反悔”。
而这,就是 Ford_Fulkerson 算法思想,以下简称 FF算法。
(因为只给了理论没给程序,只能是思想而不是算法)
【FF算法】
考虑每条边再建一条反向的边。
开始时,每条反向边的边权均为 0 。
反向边的意义是:可以反悔的额度。
比如,还是这个图。
把反向边建出来,并加上权。
假如我们走了这条横跨两大陆的边,有几条黑边输送了 1 的水,要减 1.
与此同时,这些边的反向边要加 1,即可以反悔的额度加 1 了.
于是图变成这样:
我们惊奇地发现,如果加了反向边,还能找到一条路:
如果走了这条路,我们横跨大陆的错误就纠正了。
如何翻译 “走了这条路” ?
当你走了一条反向边,相当于把来到这里的水又倒了一些出来。
这些水 “反悔” 了,换了一条路,再走一遍。
【具体实现】
我们知道了整个算法的流程,但其中还有一个问题。
我们一直在说:随便找一条路,如何找呢 ?
【直接做:EK】
就按照 FF算法 说的,我们就每次找一条增广路,然后流过去。
也就是每次从源点搜索一条到汇点的路径,然后流。
这种算法就叫做 EK(Edmonds-Karp),复杂度
【图分层:Dinic】
我们进行一个优化:先从源点 BFS,只经过剩余容量
然后找增广路时,只走那些通向下一层的边。
【当前弧优化】
非常重要!
【有上下界的网络流】
【无源汇可行流】
建立超源点
从
【有源汇可行流】
在上面图的基础上,在原来的
(这个时候我们找到了一个可行流,且这个可行流就是此时
(想知道
【有源汇最大流】
上面的图跑完最大流得到残余网络,在这个残余网络上先删掉
注1:删边
注2:具体代码实现,删边可以直接调用 e[s],e[t]
的最后一个元素,因为
※ 注3:也可以不删边直接在残余网络上求
【有源汇最小流】
也是残余网络删掉
【费用流】
一般先保证最大流,再保证最小费用。
每条边每流一单位的流量,就要付一份这条边对应的钱。
先抛弃 Dinic,回归 FF 算法。
但是这次我们每次找增广路,用最短路算法找到一条费用最小的增广路,然后增广。
注意带费用的边的反边,费用就应该是负数了,因为反边代表的是反悔,反悔就要把费用吐出来。
复杂度:
【正确性】
首先根据 FF 算法,只要是找增广路,就一定是对的。
但是是否每次找单个最小,就能得到总体最小?
是。(因为 FF 算法的反边是保证了一切反悔的可能性)
【有源汇上下界最小费用最大流】
注意建图反边费用是负数!
注:所有额外边的费用都是
类比有源汇最大流,我们建了图后先跑一遍
然后(不删边)再跑
则总共最大流量是
【题目】
Telecowmunication 奶牛的电信
这题是割点,不是割边。那怎么做?
把每个点拆成入点和出点。入点向出点连一条容量为删除这个点代价的边。
然后可以通信的点之间,入点向出点连
于是就可以最小割了。
蜥蜴
最少留下 = 总 - 最多离开。
也把每一个格子分成入点和出点,对于每个格子只能经过多少只蜥蜴,其入点就向出点连多少容量的边。
互相能跳跃的格子,连容量
除此之外,怎么分配初始蜥蜴?我们可以建立超源点
同时建立超汇点
这题里面,我们认为格子的限制只在格子内部处理,格子之间是可以无限跳跃的。同时:我们认为蜥蜴不是一开始就在格子上,而是从一个位置
士兵占领
这题王老师的 std 写错了,把行和列的结点建到一起去了。
解法:
把士兵的分配看作都从源点出发,流到每个行,然后从每个行流到每个列上面去。
对行的限制体现在
具体而言:设第
然后如果
然后求有源汇上下界最小流。
圆桌问题
构造一个图:左边
跑最大流,看看是否等于总人数。
如何找方案:循环左边每个点,再循环到右边的边,看看容量是否为
星际转移问题
之前 ZR 模拟做过类似的。
把地月看作
拆点,每个点拆成
初始源点向地球连
枚举
加了新边之后跑最大流,把最大流加入目前的人数中,判断是否达到
植物大战僵尸
神奇的建模。
先拓扑排序找出所有环和环的后继。这些一定是不会被吃的。
如果保护者指向被保护者,答案就是在剩下的点之间求最大权闭合子图。
(闭合子图:选一些点,使得如果
建模:建立超源超汇,原来保护关系的边都方向取反后变成
然后,若点
去掉拓扑排序后,所有收益为正的植物的收益之和 减去 最小割即答案。
拍照
也是最大权闭合子图。
对
类比上面,每个人都保护了一些拍照事件。
海拔
观察:最终每个点的高度要么是
观察:最后的图中,
所以我们的问题:分成两个连通块,使得联通它们的边边权和最小。
直接最小割,但是发现还要优化。
对偶图!
对偶图是一种平面图最小割的优化方法。可以把最小割转化为最短路。可以上网搜。
CF704D
思路和蜥蜴一样,每个点的颜色视作先从超级源点流到每个
点要离散化,但是不能用 map
,因为点可能重复.
餐巾计划问题
补充题意:初始没有餐巾;最后一天过了,餐巾是不是全部干净都行。
把每一天看成节点,餐巾的使用视作在节点之间流动。
具体而言,建立
(以下没说费用都是
如何连边?首先,干净点
跑上下界最小费用流即可。
深海机器人问题
难点在于怎么处理每个生物标本只能被采摘一次。
首先生物标本是在点上的,对点的限制不好直接在图上体现。我们用一个经典 trick: 入点出点。
然后对于一个生物标本,我们从入点到出点连一条容量
另外每个入点到出点,都连一条容量无穷,费用
跑最大费用最大流。
志愿者招募
我们把问题看作我们一开始有无限个志愿者。题目的“雇佣”就是让一些志愿者开始工作。设置
假如第
一类志愿者可以从
然后超源点
这么跑最小费用最大流:
首先人数有
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!