文章目录
- 前言
- 常见基本模型
- 最大匹配、最小点覆盖和最大独立集
- 构造最小点覆盖
- 最大点权匹配
- 最小路径覆盖
- 不可重覆盖
- 可重覆盖
- 最大权闭合子图
- 建图技巧
- 利用拆点进行限流
- 利用断边表示决策
- 利用虚点表示组合关系
- 链状模型
- 用链表示时间轴
- 用链表示偏序关系形式的选取限制
- 通过拆点描述先后顺序
- 改变边权实现双关键字
- 优化技巧
- 动态加点/加边优化
- 更新残量网络确定未知的答案
- 上下界网络流
- 无源汇上下界可行流
- 有源汇上下界可行流
- 有源汇上下界费用最小可行流
- 有源汇上下界最大流
- 有源汇上下界最小流
- 带负圈的网络流
前言
总所周知,网络流会写板子几乎是毛用没有的。
对于一些限制较为复杂的题,难以用贪心或者 dp 解决,此时就可以想到网络流。
数据范围上,网络流的题目点数通常不会超过 1000。
常用的技巧包括拆点、虚点等。
常见基本模型
最大匹配、最小点覆盖和最大独立集
比较简单,把左边所有点和原点连流量 1 的边,右边点和汇点连流量 1 的边,然后按照给出图连边,流量正无穷即可。
复杂度比匈牙利更为优秀。
引理:
- 最小点覆盖=n-最大独立集。
- 最大匹配=n-最大独立集。
简记就是:最大匹配=最小点覆盖=n-最大独立集,只有独立集比较独立,所以和别人长得都不一样。
(最大匹配指匹配对数,nnn 表示两边的点数之和)
首先,关于性质1,比较简单:对于任何一个点独立集 SSS,它的补集 S′S'S′ 都是一个合法的点覆盖(因为根据独立集的定义,不存在一条边的两个端点都在 SSS 中),那么要使点覆盖最小,就要使独立集最大
对于性质2,设全集为 MMM,最大匹配的点集为 PPP,最大独立集的点集为S,规定一个点集X的大小用|X|表示
那么最大匹配就是∣P∣/2|P|/2∣P∣/2
我们考虑分为两步证明:∣S∣<=∣M∣−∣P∣/2|S|<=|M|-|P|/2∣S∣<=∣M∣−∣P∣/2 和 ∣S∣>=∣M∣−∣P∣/2|S|>=|M|-|P|/2∣S∣>=∣M∣−∣P∣/2
- ∣S∣<=∣M∣−∣P∣/2|S|<=|M|-|P|/2∣S∣<=∣M∣−∣P∣/2 :比较显然,考虑在匹配中的每一对点,至少有一个点不在独立集中(因为它们互相连接),所以独立集的大小一定不会超过∣M∣−∣P∣/2|M|-|P|/2∣M∣−∣P∣/2
- ∣S∣>=∣M∣−∣P∣/2|S|>=|M|-|P|/2∣S∣>=∣M∣−∣P∣/2 :设最大匹配的补集为 P′P'P′,那么首先P‘的所有点可以加入 SSS(否则它们就可以匹配了),然后对于P中的每一对匹配点 A、BA、BA、B,考虑它们一定不能同时与 P′P'P′ 中的点有连边(否则就可以增广了,不是最大匹配),所以它们中至少一个可以加入 SSS 中。
证毕。
构造最小点覆盖
已知最小点覆盖等于最大匹配,那么如何构造出最小点覆盖的方案呢?
方法如下:
从右侧集合的未匹配点开始,寻找所有的“伪增广路”(即匹配边与非匹配边交错出现,起点和终点都在右侧,总长度为偶数),标记路径上的所有点。
最后左侧所有的标记点和右侧所有未标记点即所求点覆盖。
证明:
首先,无论是否在标记路径上,每条匹配边都有且只有一个点被选取,选取的点数等于最大匹配。
路径上的所有边都必然会被左侧的标记点覆盖;不在路径上的边都必然会被右侧的未标记点覆盖,故是一个合法的路径覆盖。
证毕。
最大点权匹配
把每个点和源/汇连边的容量由 1 改为点权即可。
最小路径覆盖
不可重覆盖
给一个DAG,请你用数量最少的互不相交的路径覆盖所有的点。
首先,每个点本身形成一条路径,然后尝试把相邻的点尽可能多的合并从而使答案更优。
注意到,每个点必然最多只有一条路径流入,一条路径流出。
把每个结点拆成入点和出点,相邻点的入点和出点连边,问题转化为二分图最大匹配问题。
可重覆盖
给一个DAG,请你用数量最少的可以相交的路径覆盖所有的点。
较一般地,假设有交的两条路径的形式为:[a1,a2,...,ana,c1,c2...,cnc,b1,b2,...,bnb][d1,d2,...,dnd,c1,c2,...,cnc,e1,e2,...,ene][a_1,a_2,...,a_{n_a},c_1,c_2...,c_{n_c},b_1,b_2,...,b_{n_b}]\space [d_1,d_2,...,d_{n_d},c_1,c_2,...,c_{n_c},e_1,e_2,...,e_{n_e}][a1,a2,...,ana,c1,c2...,cnc,b1,b2,...,bnb] [d1,d2,...,dnd,c1,c2,...,cnc,e1,e2,...,ene],那么我们可以额外连一条 (dnd,e1)(d_{n_d},e_1)(dnd,e1) 的边,使得两条路径转化为没有交。
注意到,这种加边是一种类似于传递式的加边,所以我们求出原图 GGG 的传递闭包 G′G'G′,在新图上进行不可重覆盖问题。
每个可重覆盖路径覆盖方案都可以在新图上转化为不可重路径覆盖方案,而且每种这样加边后的方案也都可以映射出一种原来的合法方案,形成双射关系,所以是对的。
最大权闭合子图
在一张有向图 VVV 中,如果对于一个点集 SSS,满足 ∀u∈S,(u,v)∈V→v∈S\forall u\in S,(u,v)\in V\to v\in S∀u∈S,(u,v)∈V→v∈S,则称 SSS 为 VVV 的一个闭合子图。
现在给每个点一个权值 viv_ivi,求这张图的最大权闭合子图。
考虑建出超级源汇 S、TS、TS、T。对于 vi>0v_i>0vi>0 的点,连一条 (S,i)(S,i)(S,i) 容量为 viv_ivi 的边;对于 vi<0v_i<0vi<0 的点,连一条 (i,T)(i,T)(i,T) 容量为 ∣vi∣|v_i|∣vi∣ 的边。原图的边原样建出,容量为 INFINFINF。(零权点无关紧要,随便那边带等即可)
由于中间原图的边全是 INFINFINF,不可能割,最终求出的最小割必然是一个简单割(也就是割边至少有一个端点是 SSS 或 TTT)。
断掉正权点的边表示我们放弃选择这个点,断掉负权点的边表示我们选了这个点并且付出了其对应的代价。
那么我们的割边方案和闭合子图的选取形成了一个双射关系,所以正权点权值和减去最小割即所求。
注意到,割出的两个点集中,包含 SSS 的点集是一个闭合图,事实上,这个集合也就是我们选取的最大权闭合子图。
建图技巧
利用拆点进行限流
P1402 酒店之王
XX 酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化。由于很多来住店的旅客有自己喜好的房间色调、阳光等,也有自己所爱的菜,但是该酒店只有 ppp 间房间,一天只有固定的 qqq 道不同的菜,每个房间只能住一位客人,每道菜也只能给一位客人食用。
有一天来了 nnn 个客人,每个客人说出了自己喜欢哪些房间,喜欢哪道菜。但是很不幸,可能做不到让所有顾客满意(满意的条件是住进喜欢的房间且吃到喜欢的菜)。
要怎么分配,能使最多顾客满意呢?
考虑把房间放在左侧,和原点连容量1的边;把饭菜放在右侧,和汇点点连容量1的边。把边的容量设置为1,从而满足每个房间或饭菜只能给一个人享用的性质。
对所有的人分别建一个点,对其喜欢的房间和饭菜分别连边。从两边任取一对形成流量,就能对应产生1的满意度
但是这里每个人只能形成1的流量,因此把每个点 xxx 拆成 x,x′x,x'x,x′ 两个点,两个点之间连一条流量为1的边,从而达到限流的目的。
code
另一道利用拆点的题目
利用断边表示决策
首先我们需要一个引理:
一个网络流图的最大流等于最小割。
证明:对于任意一个割,其流量应该不超过出边容量,故最大流小于等于最小割。
考虑跑完最大流的残量网络分出的这个割,它的容量就等于最大流,故最小割小于等于最大流。
综上,最大流等于最小割。
由此,很多时候,我们都可以从断边的角度思考问题。
情景:有 nnn 个物品,每个物品划分到 AAA 集合产生 aia_iai 的代价,划分到 BBB 集合产生 bib_ibi 的代价,求最小代价。
取个 max 不就行了。
这只是个最基本的模型,题目一般都会在这基础上加一些额外条件和限制。
把每个物品建一个点,分别往 SSS 连流量 aia_iai 的边,往 TTT 连流量 bib_ibi 的边,此时断通向 SSS 的边表示划分到 AAA 集合,反之就是划分到 BBB 集合,因此我们就是求这个图的最小割,直接跑 dinic 即可。
如果问题改为最大化,可以把问题视为使损失的价值最小,从而转化为上述模型。
利用虚点表示组合关系
P1361 小M的作物
小 M 在 MC 里开辟了两块巨大的耕地 AAA 和 BBB(你可以认为容量是无穷),现在,小 P 有 nnn 种作物的种子,每种作物的种子有 111 个(就是可以种一棵作物),编号为 111 到 nnn。
现在,第 iii 种作物种植在A中种植可以获得 aia_iai的收益,在 BBB 中种植可以获得 bib_ibi 的收益,而且,现在还有这么一种神奇的现象,就是某些作物共同种在一块耕地中可以获得额外的收益,小 M 找到了规则中共有 mmm 种作物组合,第 iii 个组合中的作物共同种在 AAA 中可以获得 c1,ic_{1,i}c1,i 的额外收益,共同种在 BBB 中可以获得 c2,ic_{2,i}c2,i的额外收益。
小 M 很快的算出了种植的最大收益,但是他想要考考你,你能回答他这个问题么?
不考虑额外收益,问题就是前面讲的利用断边表示决策的模型,向 S 连 aia_iai 边,向 T 连 bib_ibi 边。断边表示不选对应集合损失的价值。
如何在网络流图中表示额外收益呢?
假设 x1,x2,...,xkx_{1},x_2,...,x_kx1,x2,...,xk 都分到 AAA 田产生 ccc 的价值。
考虑对于每一个组合关系,建一个对应的虚点 ppp,令 SSS 向 ppp 连一条 ccc 的边,ppp 向 x1,x2,...,xkx_{1},x_2,...,x_kx1,x2,...,xk 各连一条流量 inf 的边。这样,当且仅当所有点都断掉了 TTT 方向的边(放弃 BBB 集合,选取 AAA 集合)时,SSS 与 ppp 之间的流量为 ccc 的边才得以保留,即不会损失对应的价值。
code
链状模型
用链表示时间轴
P3980 志愿者招募
申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要 nnn 天才能完成,其中第 iii 天至少需要 aia_iai 个人。布布通过了解得知,一共有 mmm 类志愿者可以招募。其中第 iii 类可以从第 sis_isi 天工作到第 tit_iti 天,招募费用是每人 cic_ici 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。
一个乍看很蒙的题。
考虑按照时间轴建图。
从 SSS 向 1 连流量 INFINFINF 的边,iii 向 i+1i+1i+1 连 INF−aiINF-a_iINF−ai 的边,n+1n+1n+1 向 TTT 连 INFINFINF 的边。这些费用均为 0。
对于每种雇员,连一条 sis_isi 到 tit_iti,流量 INFINFINF,费用 cic_ici。
为什么这样是对的?
考虑这是如何体现每个节点的要求 aia_iai 的。
因为链上容量改变的原因,必然有容量为 aia_iai 的流”不走寻常路“。
换句话说,它一定是从跨过点 iii 的员工雇员边流走的,这完美的匹配了我们这个问题的要求。
code
另一道不错的链状模型的题目
用链表示偏序关系形式的选取限制
P6054 开门大吉
nnn 位选手去参加节目“开门大吉”。共有 mmm 套题,每套题包含 ppp 个题目,第 iii 位选手答对第 jjj 套题中第 kkk 道的概率为 fi,j,kf_{i,j,k}fi,j,k。
若一位选手答对第 iii 题,会在已得到奖励的基础上,再得到 cic_ici 元奖励。选手总是从第一道开始,按顺序答题的。
同时,为了防止过多的选手做同一套题,还有 yyy 条形如“第 iii 位选手的套题编号必须至少比第 jjj 位的大 kkk”的限制。
你需要给每一位选手分配一套题(不同选手可以相同),使得所有人的期望奖励和最小。
首先,我们可以简单的算出 iii 选手选套题 jjj 的期望价值 vi,jv_{i,j}vi,j。
关键就在于如何表示限制。
建出 nnn 条长度为 m+1m+1m+1 的链,设链上的点为 p1...n,1..m+1p_{1...n,1..m+1}p1...n,1..m+1,连边 (S,pi,1,INF),(pi,m+1,T,INF),(pi,j,pi,j+1,vi,j)(S,p_{i,1},INF),(p_{i,m+1},T,INF),(p_{i,j},p_{i,j+1},v_{i,j})(S,pi,1,INF),(pi,m+1,T,INF),(pi,j,pi,j+1,vi,j)。断掉 (pi,j,pi,j+1,vi,j)(p_{i,j},p_{i,j+1},v_{i,j})(pi,j,pi,j+1,vi,j) 的边即表示令 iii 选手做 jjj 号题。
这样建图之后限制就容易表示了,设 iii 选手比 jjj 选手题目编号至少大 kkk,就对于所有合法的下标 xxx,均连边 (pj,x,pi,x+k,INF)(p_{j,x},p_{i,x+k},INF)(pj,x,pi,x+k,INF) 即可。
本题更详细的题解(对本题一些处理细节的讨论)
通过拆点描述先后顺序
P2053 修车
同一时刻有 NNN 位车主带着他们的爱车来到了汽车维修中心。
维修中心共有 MMM 位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。
现在需要安排这 MMM 位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。
对于每个人的等待时间不好考虑,转而考虑每辆车会对答案产生多少贡献。
不难看出,如果第 iii 辆车是第 jjj 位技术人员倒数第 kkk 个修的,那么就会产生 k×costi,jk\times cost_{i,j}k×costi,j 的代价。
那么我们把每个技术人员拆成 kkk 个点,每个点表示倒数第 kkk 个进行的工作,每个结点连的边的费用也就乘以对应的 kkk 倍。
由于费用流的最优性,这些点一定是顺次选取的。
code
改变边权实现双关键字
P1344 追查坏牛奶
给出一张网络流图,求最小割和最小割前提下的最小割边数。
设置一个大于边数的常数 CCC。
对于每条流量为 www 的边,设置其边权为 w∗C+1w*C+1w∗C+1。
这样就能保证在保证最小割的前提下使边数最小。
code
优化技巧
动态加点/加边优化
P2050 美食节
题意和上面的修车是一样的,只不过调大了数据范围,每种车有 pip_ipi 辆,像刚才那么暴力加边无法通过。
注意到,我们加的点和边存在大量的浪费,很多点根本是不可能用到的。
所以,我们一开始只建出 k=1k=1k=1 的点,然后每次增广之后寻找到本次增广用到点,把其再往后开一个。
这样一共只会开 ∑pi\sum p_i∑pi 个点。
code
更新残量网络确定未知的答案
P2754 [CTSC1999]家园 / 星际转移问题
由于人类对自然资源的消耗,人们意识到大约在 2300 年之后,地球就不能再居住了。于是在月球上建立了新的绿地,以便在需要时移民。令人意想不到的是,2177 年冬由于未知的原因,地球环境发生了连锁崩溃,人类必须在最短的时间内迁往月球。
现有 nnn 个太空站位于地球与月球之间,且有 mmm 艘公共交通太空船在其间来回穿梭。每个太空站可容纳无限多的人,而太空船的容量是有限的,第 iii 艘太空船只可容纳 hih_ihi 个人。每艘太空船将周期性地停靠一系列的太空站,例如 (1,3,4)(1,3,4)(1,3,4) 表示该太空船将周期性地停靠太空站 134134134…134134134\dots134134134…。每一艘太空船从一个太空站驶往任一太空站耗时均为 111。人们只能在太空船停靠太空站(或月球、地球)时上、下船。
初始时所有人全在地球上,太空船全在初始站。试设计一个算法,找出让所有人尽快地全部转移到月球上的运输方案。
容易想到每个时间都建一套点。
然而,我们不确定最终的答案会是多少,难以直接建出最终的图。
考虑枚举最终答案,每次多建一层图,在残量网络跑网络流,直到流量达到 kkk 为止。
code
上下界网络流
名字看起来很高大上的算法,但其实都只是在最大流或费用流的基础上加一些小技巧罢了。
无源汇上下界可行流
对于一条边 (u,v,mn,mx)(u,v,mn,mx)(u,v,mn,mx) 先把每条边的下界 mnmnmn 流满(不妨叫它基础流量),然后加一条 (u,v,mx−mn)(u,v,mx-mn)(u,v,mx−mn) 的边。
设每个点 基础流入量减去基础流出量的值为 ddd。
为了满足网络流流入等于流出的要求,我们需要把所有 d≠0d\ne 0d=0 点的流量平衡掉。换句话说,对于一个 d>0d>0d>0 的结点 xxx,我们需要它在多往外流 ddd 的流量,那么我们就建一组超级源汇 S、TS、TS、T,连一条 (S,x,d)(S,x,d)(S,x,d) 的边;类似的,对于一个 d<0d<0d<0 的结点 xxx,连一条 (x,T,d)(x,T,d)(x,T,d) 的边。
然后在新图上跑网络流即可,如果无法满流说明无解。
有源汇上下界可行流
源汇点和正常结点的区别就在于它们不必满足流出等于流入。
连一条 (T,S,0,INF)(T,S,0,INF)(T,S,0,INF) 的边,然后当成无源汇即可。新连的这条边的流量也就是原图的流量。
(注意这里提到的源汇都是指原图的源点汇点而不是超级源汇!)
有源汇上下界费用最小可行流
我们需要什么?
再新图满流的前提下费用最小,也就是流最大的前提下费用最小。
这不就是费用流嘛。
把最大流直接改成费用流就好啦。
有源汇上下界最大流
先求出任意一个可行流,记录其流量为 flow1flow1flow1(注意是真实流量!)
然后在把 (T,S,0,INF)(T,S,0,INF)(T,S,0,INF) 这条边去掉,跑一个 S→TS\to TS→T 的最大流,设为 flow2flow2flow2。
最终的答案就是 flow1+flow2flow1+flow2flow1+flow2。
有源汇上下界最小流
和最大流几乎一样,最后改为跑 T→ST\to ST→S 的最大流,答案为 flow1−flow2flow1-flow2flow1−flow2。
带负圈的网络流
本来以为可能会很恶心,但结果发现又是一个小清新?
这个问题中,我们认为不与源汇联通的环的整体加减流也是合法的。
对于一条负边,我们强制使其满流,然后再反向连一条返回边。
然后跑上下界网络流就行了。