网络流 & 二分图 & 线性规划

网络流

  1. P4177 [CEOI2008]order
    题意 :有 ​ 个工作, ​ 个机器, 每种机器可以租或者买, 给定 ​ 个工作的收益, 需要的机器和此次租这台机器的费用, 求最大化利益。

显然, 如果没有租的要求的话, 那么就是一个最大权闭合子图模板。

最大权闭合子图 :一个有向图,点有点权,选一个点必须要选它的所有后继, 求最大权值和。

具体建图 :新建一个源点 S 和汇点 T,将 S 与所有点权为正的点连边,流量为 ​, 并累加权值, 将 所有点权为负的点向 T 连边, 流量 ​。对于原图,建 ​,流量 ​ 的边, 将累加的权值减去最大流 / 最小割既是最大权值和。

对于点权为正且无残余流量的点来说, 它没有被选,否则被选。

对于点权为负且无残余流量的点来说, 它被选, 否则没被选。 可以根据此输出方案。

好了, 这个题还有租的机器的方案,因为买对所有工作都有效, 租只对当前工作有效, 那么就把流量为 ​ 的改成租的代价再跑一遍最大流即可。

用最小割理解可能更简单一些。

2.P3749 [六省联考 2017] 寿司餐厅
题意 : ​ 种寿司, 每种寿司有一个代号 ​ 和一个美味度 ​,你可以不限次数吃一段区间的寿司, 收益为 ​, 每种收益 ​ 只能算一次。

假设最后你吃了 ​ 种代号为 ​ 的寿司, 你要支付的代价为 ​, ​ 是给定的一个常数。

最大化收益 - 代价。

发现每种收益只能算一次这个现在比较奇怪, 而且要求的是收益 - 代价, 不难想到最大权闭合子图。

考虑怎么把这个图建出来 :你要得到 ​ 的收益, 那么一定得到了 ​ 和 ​ 的收益,因为你选择的是一段段的区间,那么就从 [i, j] 连向 [i,j - 1] 和 [i + 1, j],再对 ​ 的收益正负考虑它是从 S 连出来还是向 T 连过去。

把代价放在单点上考虑, 每吃一个代号为 ​ 的, 那么就要付出 ​ 的代价, 因为代号的 ​ 也只能算一次, 再把单点连向它的代号, 代号的代价即是 ​,跑出最大流即可。

3.P1361 小M的作物
题意 : ​ 种作物, A,B 两块地,每种作物只能种在一块地里面, 会有不同的收益。

另外有 ​ 种组合方式, 表示把该种组合的所有作物都种在一块地里面会有额外收益。

求最大收益。

二选一模型, 可以考虑最小割。

先考虑没有额外收益的情况 :源点表示选 A,汇点表示选 B,每个点与 S, T 分别连边, 流量为分别的权值, 最后用总和 - 最大流即可。

再考虑加入点集的答案, 这个点集无非只有三种情况 :

1.全种在 A 中,有 ​ 的贡献。 2. 全种在 B 中, 有 ​ 的贡献。 3. 只有部分在 A,无贡献。

我们考虑建出一个虚点来表示这个集合,分别与 S, T 相连边, 再与集合中所有的点连边, 边权为 ​ , 表示这些边不能被删。

那么跑完最小割后, 如果边权为 ​ 的边没有割去,那么这些点一定都属于集合 A。 如果边权为 ​ 的边没有割去, 那么这些点一定都属于集合 B,那些边权为 ​ 的边一定不会被删。

感性理解即可,对于这种模型一定要多积累和多练。

4.P2764 最小路径覆盖问题
题意 :给你一张 DAG, 设 ​ 是 ​ 的一个简单路的集合, 如果 ​ 中每个点都恰好在 ​ 中一条路径上, 则称 ​ 是 ​ 的一个路径覆盖, ​ 的最小路径覆盖即是所含简单路最少的 ​。

一个有向无环图的一条路径, 可以表示为除终点之外的所有点, 都向外伸出一条边。

把每个点拆成两个点 :入点和出点, 分别用 ​ 和 ​ 表示,放在一个二分图里面。

那么一条路径就是起点 ​ 没有匹配, 终点 ​ 没有匹配, 其他全部匹配的若干点。

可以发现 ​ - 最大匹配数就是最小路径覆盖数, 输出方案就直接在右部点 DFS 即可。

5.P6061 [加油武汉]疫情调查
题意 :一个有向图, 边有边权, 每一个人要分配一些点集, 这个人就按照给定的顺序依次经过这些点并回到起点, 你要分配这些人, 使得他们的点集是一个 ​ 的划分。 特别地, 若一个人只分配到了一个点, 那么花费是 ​。

求最小代价。 ​

可以发现一个人经过的路程是一个环, 还是若干个不相交的环, 这不就是最小环覆盖吗 ?

于是有一个很自然的想法 :先用 floyd 求出两两之间最短路, 再跑最小费用最大流, 因为可以走自环, 所以肯定是会满流的。

但这样做会超时,因为点数有 ​, floyd 就有 ​ 的复杂度, 考虑优化。

考虑减少边的数量, 具体的, 我们想用最小费用最大流的机制让它自己求出最短路。

具体建边如下 :

从 S 向每一个 ​ 连一条流量为 ​, 费用为 ​ 的边。

每一个 ​ 向 ​ 连一条流量为 ​,费用为 ​ 的边,反向连流量 ​, 费用为 ​ 的边。

每一个 ​ 向 T 连流量为 ​, 费用为 ​ 的边。

对于原图上的边 ​, 建边 ​,流量 ​,费用为 ​。

优化后边数为 ​ 级别的, 可以通过。

6.P5038 [SCOI2012]奇怪的游戏
题意 :一个 ​ 的网格图, 初始每个格子上有一个值。 每次选择两个相邻的格子权值加 ​, 求最少次数使得所有数变成同一个数。

看到网格图先进行黑白染色成二分图, 则每次操作只会在一黑一白中进行,所以最后黑白所增加的权值一定相等。

假设黑色点有 ​ 个, 总权值为 ​, 白色点有 ​ 个, 总权值为 ​,设最后达到相同的数是 ​, 则满足等式 : ​,得到 ​, 分类讨论 :

若 ​ , 则 ​ 可以直接算出来,再检验 ​ 的合法性, 具体地 :

建立源点 S,汇点 T,把每一个黑点要加的值 ​ 作为流量与 S 相连,表示要加上这么多次才能使该点满足, 对于白点同理,再从黑点向四周连白点, 跑最大流。

当入边和出边都满流时合法。

若 ​,此时点的总数一定是偶数, 相当于 ​ 至少有一个为偶数, 此时满足单调性 :若 ​ 成立, 则 ​ 也成立, 因为可以把每个格子都加上 ​, 二分即可。

需要注意的是二分的上界要开的很大, 具体证明要用 Hall 定理, 这个之后再讲。

7.P2053 [SCOI2007]修车
题意 : ​ 个车主来修车, ​ 个技术人员维修。 第 ​ 辆车由第 ​ 个人维修要 ​ 的时间。

安排 ​ 个技术人员的维修的车和维修的顺序, 使得平均等待时间最小 。

显然一个人等待的时间就是他的技术人员修之前车时间的总和。

设第 ​ 个技术人员分别修了 ​ 个车, 则总时间为 :

​, 也就是越先修的时间代价越高,倒数第 ​ 个修的时间系数为 ​。

那么把每一个技术人员拆成 ​ 个点, 表示他在修倒数第 ​ 个人的车的状态。

那么源点 S 连向所有的车, 流量为 ​, 每一个拆出来的点都与这 ​ 个车连边, 费用为 ​, 其中 ​ 表示拆的是倒数第 ​ 个点, 再向汇点 T 连边, 流量为 ​。

跑最小费用最大流即可。

可以证明最终选取的拆的点一定是连续的, 否则会不优。

8.P2050 [NOI2012] 美食节
题意 : 与 修车一模一样, 但数据范围大了许多。

考虑我们没有必要一次性把所有的边和点建出来,于是在最开始的时候只用把每一个厨师的倒数第一次的点建出来。

在 SPFA 找增广路时, 肯定只有一个厨师是匹配的, 于是我们把这个厨师的下一个时间段建出即可。

动态开点来优化费用流,是一个不错的优化方法。

9.CF976F Minimal k-covering
题意 : 一张二分图, 对于所有 ​, 求出使所有点的度数 ​ 需要保留边的最小数量,输出方案。

按照题意, 要求的是上下界最小流,但对于每一个 ​ 算一遍答案复杂度不对。

我们发现是度数至少为 ​ 限制了我们, 考虑怎么去掉它 ?

把至少转化为至多,那么就表示一个点至多去掉 ​ 条边,那么对于 ​ 从大到小考虑, 每次会把所有 ​ 点的从 S 流向它的流量加一,再在残量网络上增广。

那么这样的复杂度就是 ​ 了, 具体不会证明

10.P3980 [NOI2008] 志愿者招募
题意 : 给定一个序列 ​, 初始均为 ​, 你可以执行 ​ 种操作, 每次把区间 ​ 的值增加 ​,费用为 ​,可以任意次执行。 最后要求所有的 ​,求最小费用。

费用流, 考虑怎么建边 :

发现这个至少不好满足, 考虑求至多, 具体建边如下 :

从 S 连向 ​, 容量为 ​ (​ 不小于最大的 ​) 。

对于每一个 ​ 连向 ​, 容量为 ​,表示第 ​ 个下标至多不流 ​ 个流量。

从 ​ 连向 T, 容量为 X。

对于每一个限制 ​, 从 ​ 向 ​ 连边,容量为 INF, 费用为 ​。

跑一次最小费用最大流即可。

拓展 :

我们将这个问题形式化 :给定 ​ 的 ​ 个区间 ​, 每个区间选择一次的代价为 ​,最多选择 ​ 次, 最后要求点 ​ 的覆盖次数在 ​ 间, 求最小 / 最大代价。

同样把 ​ 连成一条链, 先确定最大流量 X。

用 ​ 边的流量刻画 ​ 被覆盖的次数, 流量要求在 ​。

对于一个区间, 建边 ​, 容量为 ​, 费用为 ​。

  1. P6967 [NEERC2016]Delight for a Cat
    题意 : 一只猫在连续的 ​ 个小时内进行睡觉或进食两种动作, 一小时只能选一个。在每小时的收益分别为 ​。

要求在连续 ​ 个小时内, 必须要有至少 ​ 的时间睡觉和 ​ 的时间进食, 求最大收益。

先强制每个小时都睡觉, 再把一些睡觉改成进食, 对于每个区间要改的个数在 ​ 之间。

把每连续 ​ 个小时 ​ 看成点, 把修改一个小时 ​ 对点 ​ 看做区间。

那么最后就要求每个点覆盖的次数在 ​ 之间, 把 X 当做 ​ 后就没有下界了。

  1. P3511 [POI2010]MOS-Bridges
    题意 :一个图, 边有正走和逆走的权值, 求一个最大边权最小的欧拉回路并输出方案。

​ 先二分答案, 就变成了一些边只能倒着走, 一些边只能正走, 还有一些边随便走的混合图欧拉回路。

一个图存在欧拉回路的充要条件是每个点入度 = 出度,先把无向边任意选一个方向变成有有向边,再从 ​ 连一条容量为 ​ 的边, 表示反悔。

若发现有点的度数为奇数则无解。

否则, 如果一个点入度 - 出度 > 0,说明入边太多, 从 S 连向 ​, 流量为 ​

如果一个点 < 0,说明出边太多, 从 ​ 连向 T,流量为 ​。

最后如果所有边满流则有解,输出方案请左转模板【欧拉路径】。

13.P2304 [NOI2015] 小园丁与老司机

14.P4542 [ZJOI2011]营救皮卡丘

15.P2469 [SDOI2010]星际竞速

16.P4194 矩阵

17.CF1288F Red-Blue Graph

18.CF708D Incorrect Flow

模拟费用流 Begin
先证明几个定理:

费用流的凸性 :根据 EK 算法, 每次增广的花费会不断增长,以费用为纵轴, 增广次数为横轴, 则画出来的图像是一个凸函数。

最小费用任意流 :每次增广负数费用路径直到费用为正。

(增量)最小费用任意流:每次往图中加入一个点和若干边, 并求解新的最小费用任意流。

我们只用考虑 "负路径" 和 "负环" 所造成的贡献。

可以用堆来维护已经增广过的路径和没有增广路径的最大值,具体方式因题而异。

费用流常用算法的效率较为低下,只能处理较小的数据范围。在一些特殊的费用流模型中,可以利用题目的特殊性质,结合数据结构 等技巧,设计更高效的费用流算法,称之为“模拟费用流”。

  1. P4694 [PA2013] Raper
    题意 :有两个序列 ​ 和 ​, 每个 ​ 可以和 ​ 的 ​ 匹配, 收益是 ​, 求匹配 ​ 对的最大收益。 ​。

很容易建出一个费用流模型, 但显然是过不了的。

考虑模拟费用流, 每次枚举 ​, 把所有的 ​ 和已经匹配的 ​ 放到一个堆里面, 每次尝试取出最大值与 ​ 匹配, 若费用 ​ 则累加, 并把 ​ 放进堆里。

正确性可根据费用流增广得知。

  1. P5470 [NOI2019] 序列
    题意 :两个序列 ​ 和 ​, 你需要在两个序列里分别选择 ​ 个下标, 要求至少有 ​ 个下标在两个序列中都被指定, 最大化选择的 ​ 和 ​ 的和。 ​。

既然要模拟费用流, 就先把暴力费用流建出来。

从源点 S 向 ​ 中的下标连边, 流量为 ​, 费用为 ​。

每一个 ​ 向对应的 ​ 连边, 流量为 ​,表示选择了一对下标相同的数。

建立额外两点 ​, 连边 ​,流量为 ​, 表示最多允许 ​ 个 ​ 匹配不同的 $b。

所有 ​ 向 ​ 连边, ​ 向所有 ​ 连边, 流量为 ​。

再限制初始流量为 ​, 跑一遍最小费用最大流即可。 可以获得 64 pts 的高分(在考场上已经很高了)

看看这个图怎么找增广路, 具体来说, 有一下五种形式的增广路(找 cmd 贺的):

第一种方式表示 ​ 和 ​ 匹配;第二种方式表示 ​ 和 ​ 匹配 (i != j),要保证 ​ 有剩余流量;

第三种表示一个没选 ​ 但选了 ​ 的下标和一个没选 ​ 但选了 ​ 交换匹配 : ​ 匹配 ​,​ 匹配 ​, 增加一点剩余流量。

第四种表示一个没选 ​ 但选了 ​ 的下标和 一个未匹配的 ​,让 ​ 和 ​ 匹配, ​ 原先匹配的点匹配 ​。

第五种类似, 表示一个没选 ​ 但选了 ​ 的下标和一个未匹配的 ​, 让 ​ 和 ​ 匹配, ​ 原先匹配的点匹配 ​。

注意 :因为第二种匹配方式会减少一点自由流量, 要先保证 1, 3, 4, 5 种增广方案都不如第 2 种时再选择第 2 种。

考虑用 5 个堆 ​ ,分别表示 ​ 和 ​ 都没选的 ​。

​ 没选的 ​, ​ 没选的 ​, ​ 没选但 ​ 选了的 ​, ​ 选了但 ​ 没选的 ​。

每次选出最优的合法的方式增广, 注意第二种方式增广要使自由流量 -1,第三种方式增广使自由流量 +1, 选择后再更新第 4, 5 个堆的答案即可。

  1. CF436E Cardboard Box
    题意 : ​ 个关卡,每个关卡可以花 ​ 的代价得到一颗星, 或者花 ​ 的代价得到两颗星星,或者什么都不做。

求获得 ​ 颗星星最小代价。 ​。

似乎本题不能用费用流模型来刻画。

依然考虑模拟费用流 / 反悔贪心,每次增广 ​ 颗星星, 我们有这么几种方式 :

把一个选 ​ 颗星的选 ​ 颗星,代价为 ​。

把一个选 ​ 颗星的选 ​ 颗星, 代价为 ​。

把一个选 ​ 颗星的降为选 ​ 颗星, 再把另一个选 ​ 颗星的选 ​ 颗星,代价为 ​。

把一个选 ​ 颗星的降为选 ​ 颗星, 再把另一个选 ​ 颗星的选 ​ 颗星,代价为 ​。

于是用 5 个堆分别维护 没选的 ​,选了 1 个的 ​, 选了 1 个的 ​,选了 0 个的 ​, 选了两个的 ​ 的最大值。

每次增广时找最大值即可, 写起来很舒服。

22.UOJ #455. 【UER #8】雪灾与外卖
23. CF280D k-Maximum Subsequence Sum
模拟费用流 End
24.P5458 [BJOI2016]水晶
25.P5331 [SNOI2019]通信
26.P4382 [八省联考 2018] 劈配
27.CF793G Oleg and chess
28.P5039 [SHOI2010]最小生成树
29.P6054 [RC-02] 开门大吉
30.P3756 [CQOI2017]老C的方块
31.P3973 [TJOI2015]线性代数
32.P5295 [北京省选集训2019]图的难题
33.CF103E Buying Sets
34.CF786E ALT
35.CF981F Round Marriage
36.P4066 [SHOI2003]吃豆豆
37.P4003 无限之环
38.

二分图
一些定义 & 定理
定义
图的匹配 :选出一些边,使得每两条边之间没有公共端点。

图的独立集:选出一些点, 使得每两个点之间没有边相连。

图的点覆盖 :选出一些点, 使得每条边至少有一个端点被选。

图的边覆盖:选出一些边, 使得每个点都至少被一条边覆盖。

图的团:选出一些点, 使得每两个点之间都有边相连。

定理
二分图最大匹配 : 匈牙利算法

每次找到增广路,把在匹配 P 中的边和不在匹配的边的状态

反,对于每一个左部点 DFS 寻找 即可,时间复杂度 ​。

二分图最小点覆盖 :等于最大匹配

Proof : 建立二分图匹配后, 每一个最小割都对应了一个点覆盖,对于中间一条边权 ​ 的边, 其左右至少会割一个点, 由于最小割等于最大流, 故得证。

二分图最大独立集 :等于总点数减去最小点覆盖。

Proof :任何一组独立集取补后得到一组点覆盖, 独立集和点覆盖一一对应。

二分图最小边覆盖 :等于最大独立集。

图的最大团 :等于补图的最大独立集。

二分图完美匹配 :若两侧点集分别为 X,Y,匹配数达到 ​ 的匹配称为完美匹配。

Hall 定理:
假设 ​,令 ​ 表示与 ​ 相邻的点集,二分图存在大小为 ​ 的完美匹配当且仅当 ​,有 ​。

Proof :

充分性 :若不存在一个大小为 ​ 的匹配,则从左部选出一个非匹配点出发进行增广,设访问到的左部点集合为 ​,右部点集合为 ​,由于无法增广成功所以增广过程的递归终止点必然在 ​ 中,但由于 ​, 必然可以继续增广, 矛盾。

必要性 :若存在完美匹配, 设 ​ 为 ​ 的匹配点, 则 ​ 两两不同, 对于任意点集有 ​。

推论 : 二分图最大匹配为 ​。

例题
1.P2423 [HEOI2012]朋友圈
题意 : 有两个国家 A 和 B,国家的每个人有一个值 ​。

对于 A 国, 若 ​,则 ​ 和 ​ 有连边。

对于 B 国, 若 ​ 或者 ​ 为奇数, 则 ​ 和 ​ 有连边。

此外, 还有 ​ 个关系表示 A 的 ​ 和 B 的 ​ 有边。

求最大团。

最大团不好直接做, 考虑建出补图, 求一个最大独立集即可。

把所有点按照奇偶分为两个集合。

对于 A 的补图, ​ 的内部互相连边, ​ 的内部互相连边, ​ 之间没有连边,故要选 ​ 的话只能选 ​ 个。

对于 B 的补图, 若 ​ 为偶数且 ​ , ​ 奇偶不同才有连边, 发现这是一个二分图。

利用二分图最大独立集 = 总点数 - 最大匹配即可。

于是枚举 A 中选哪些点, 那么 A 中选的点连向的 B 的点都不能选, 跑一遍最大匹配即可。

2.P3488 [POI2009]LYZ-Ice Skates
题意 :给定常数 ​,初始有 ​ 的鞋子各 ​ 双, 一个号码为 ​ 的人可以穿一双编号在 ​ 的鞋子。

有 ​ 次操作, 每次有 ​ 个号码为 ​ 人来,求是否所有人都能穿一双鞋。 ​

容易建出一个网络流模型 :源点 S 向每个号码连边, 流量为拥有这个号码的人数, 每个号码 ​ 向 ​ 的鞋子连边, 每个鞋子向汇点 T 连边, 流量为 ​, 那么有解就相当于所有边满流,但点数 ​ 显然是不可能的。

考虑我们只用知道是否满流, 于是使用 Hall 定理, 贪心的选择的 ​ 一定是一段连续的区间,否则一定不优。

于是我们要检验是否对于每个区间 ​ 都有 ​,相当于 ​, ​ 是一个常量不用考虑,把每一个 ​ 减去 ​ 后就是一个最大子段和问题, 使用线段树维护即可。

3.[ARC076D] Exhausted?
题意 : 一张二分图,左部 ​ 个点, 右边 ​ 个点。 左部每个点能和编号在 ​ 或 ​ 的右部点匹配, 求最大匹配数。 ​ 。

利用 Hall 定理, 我们只要求出最大的 ​ 即可。

先对所有线段按左端点从小到大排序,枚举左端点时维护右端点的答案。

先考虑 ​ 和 ​ 不交的情况 :枚举 ​, 则所有右端点 ​ 的点肯定都要选才更优,于是使用线段树。

类似扫描线, 每次把右端点 ​ 的值加 ​, 假设枚举的左端点是 ​, 则对答案的贡献是 ​, 把左边的值设为线段树维护的值即可。

再考虑 ​ 有交, 此时 ​ 确定, 我们只要贪心地选取所有点即可。

  1. CF1009G Allowed Letters
    题意 :给定一个长度为 ​ 字符串, 字符集在 'a' - 'f', 重排这个字符串。有 ​ 个限制 :

给定 ​ 和字符集 ​, 表示第 ​ 位上只能选字符集 ​ 里的字符。

求字典序最小的字符串。 ​。

先考虑暴力网络流 :从源点 S 向每个位置连边, 每个位置向所能选的字符连边, 每个字符和汇点 T 连边, 容量为这个字符在大串的出现次数,若所有边满流则有合法解。

再考虑字典序最小 :可以贪心,从左往右枚举每个位置的字符, 再用网络流验证即可。

发现我们只想知道这个网络流是否满流, 相当于存在完美匹配。

而且字符集 'a' - 'f' 只有 6, 很难不想到枚举右部点的子集, 验证是否所有 ​ 即可。

于是做法就很显然了 :先预处理出每个右部点状态与左边匹配的个数, 可以求一个后缀和 ,再贪心地选取最小的字符, 再判断选出后的所有右部点合法即可。

5.P1963 [NOI2009] 变换序列
题意:给定 ​ 个数的一个序列 ​。

构造一个字典序最小的 ​ 阶排列 ​ ,满足 ​。

发现每个点匹配的只有两个点, 直接倒序模拟匈牙利算法,即可保证字典序最小。

6.P5292 [HNOI2019]校园旅行
题意:一张图,每个点有一个 0 / 1 的编号。

多次询问, 每次询问给出 ​, 询问 ​ 之间是否存在一条路径使得把路径上所有的编号写成 01 串后为一个回文串。

  1. [AGC013F] Two Faced Cards
    线性规划
    参考了 fjzzq 的博客,在这里膜拜他!!!
posted @ 2022-03-10 20:27  henrici3106  阅读(279)  评论(0编辑  收藏  举报