网络流题目乱做
最大流
- 直接网络流可以确定物品的分配的方案:"[POI2010] MOS-Bridges"[1]
- 环的限制可以转化为二分图匹配:"Luogu6061 [加油武汉]疫情调查"[2]
- 每条流量可以表示为一种不交的方案:"Luogu3358 最长 k 可重区间集问题"[3]
- 扩域可以很好地解决冲突:"Luogu3358 最长 k 可重区间集问题"[3:1]
最大权闭合子图
- 注意观察,矩阵可以转化为图论的选 or 不选的问题:"[TJOI2015] 线性代数"[4]
- 最大权闭合子图中,贡献为负数,就默认不计算,选择就会扣除贡献,如果为正数,就默认计算,不选就会扣除贡献:"[NOI2009] 植物大战僵尸"[5]
最小割
普通最小割
- 可以尝试建出最小割图,然后可以考虑分析最小割数量关系:"CF103E Buying Sets"[6]
- 最小割数量比较小的时候,就是两个点之间的关系比如联通/点双联通/点三联通了:"[CERC2015] Juice Junctions"[7]
最小割树
- 板子:"最小割树"[8], P4123 [CQOI2016]不同的最小割,P3329 [ZJOI2011]最小割,UVA11594 All Pairs Maximum Flow
- 分析最小割树上的情况,确定贪心方案:"CF343E Pumping Stations"[9]
上下界网络流
对偶图最短路
Hall 定理
- 线段树维护 Hall 定理的式子:"[POI2009] LYZ-Ice Skates"[10]
- 集合具有完备匹配这一性质支持加法:"[CERC2016] 二分毯 Bipartite Blanket"[11]
网络流 + 数据结构
- CDQ 同时对于跨过中点的点对连边:"[SNOI2019] 通信"[12]
[POI2010] MOS-Bridges
有 个点和 条边,每条边有两个权值,分别表示从 到 和从 到 的边权。
求图中的一个欧拉回路,使得回路中的最大边权最小,并输出方案。
考虑二分答案,转化为判定性问题。
我们先连最小代价方向的边 ,如果另外方向的边可以用,那么就可以让 ,因此我们可以把度数按照大小分类,接着跑网络流即可。(前提是所有节点 )
有几个细节:
- 最后输出方案的时候不能混合型的欧拉回路,应该根据网络流流量情况建边跑有向图欧拉回路。
- 二分之前一定要判断这个图是否是弱联通的。
Luogu6061 [加油武汉]疫情调查
给一个有向图,求用若干个环(或点)将整张图覆盖的最小花费,环的代价就是环长,点的代价就是点的权值。
。
想到基环树,我们会想到什么呢?就是环!如果基环树上的每个点的出边只有一条,且互不相同,那么就是若干个环以及自环了,这个就是匹配!
考虑一张二分图,每个左部点和右部点的边权为其距离(如果编号相同,则为点权),那么题目的限制就是求一个完美匹配。
为什么呢?因为把匹配边连起来,一定形成环和若干个单点。
于是比较暴力的想法:直接建图,然后 KM 或者费用流,复杂度 ,因为新的 已经到了 级别。
大概率会被卡,考虑更加简单的做法:拆点,连边 ,最后一条边就方便了环的限制的刻画。
跑费用流即可,复杂度 。 ↩︎
Luogu3358 最长 k 可重区间集问题
给定实直线 上 个开区间组成的集合 ,和一个正整数 ,试设计一个算法,从开区间集合 中选取出开区间集合 ,使得在实直线 上的任意一点 , 中包含 的开区间个数不超过 ,且 达到最大( 表示开区间 的长度)。
这样的集合 称为开区间集合 的最长 可重区间集。 称为最长 可重区间集的长度。
对于给定的开区间集合 和正整数 ,计算开区间集合 的最长 可重区间集的长度。
。
我们可以按照将方案划分为 个两两不相交的区间组,因此,可以考虑如下建图:
[TJOI2015] 线性代数
为了提高智商,ZJY 开始学习线性代数。
她的小伙伴菠萝给她出了这样一个问题:给定一个 的矩阵 和一个 的矩阵 。求出一个 的 01 矩阵 ,使得 最大,其中 为 的转置,输出 。
注意到 是一个 矩阵,那么可以代表选或者不选,因此 的意义就是 同时选的收益, 的意义就是 的代价,接着就是最大权闭合子图了。 ↩︎
[NOI2009] 植物大战僵尸
给出一个 的网格图,每个点有一个植物,每个植物有其价值 (可能为负数),然后有其保护位置(植物不死,僵尸就不能到那里),现在僵尸只能从某一行最后一列开始进攻并且吃掉植物,最大化僵尸最后的收益。
最大权闭合子图板子。
考虑先 拓扑排序,删掉那些永远不可能吃的位置,如果最后某个植物和 联通,那么就是会被吃,否则与 联通,就不被吃。
- : ,
- :
CF103E Buying Sets
有一个大小为 的全集,每个元素是一个数,有 个子集。题目保证任意 个子集的并的大小 。
每个子集有一个可正可负的权值,你需要选出一些子集使得这些子集并的大小等于子集个数,且所选子集的权值和最小。可以为空集。
神仙转换.jpg
有一个比较奇怪的事情, 个子集。
我们考虑源点向每个集合连边,边权为 ,如果割掉就代表不选,每个集合向数连边 ,数向汇点连边 。跑最大流,假设边权全是正的,因为有完备匹配,那么割边条数一定 ,又边权到了 ,那么割边数目 ,因此割边数目 。
因此不选的集合 + 选的数字 = ,也就是 并集大小 = 集合个数。最后贡献取反即可。 ↩︎
[CERC2015] Juice Junctions
给出一张 个点, 条边的无向图,每条边边权为 ,每个点度数不超过 ,求 。
度数不超过 ,也就说明最小割不超过 3。
分集中情况进行讨论:
- 如果两个点不连通,那么答案为 。
- 如果两个点联通,但是进行并不属于同一个点双联通分量,那么为 。
- 如果两个点是属于同一个点三联通分量,那么为 ,否则为 。
现在的问题就是如何判断两个点是否属于同一个点三联通分量了。
注意到 ,于是可以考虑暴力删掉一条边,然后去判断每个点的点三联通分量情况,共 轮,每个点可以存一个 Hash 值,时间复杂度 。 ↩︎
最小割树
构建方法
每次
rand
两个点 ,然后求出这两个点之间的最小割,在最小割树上连边 ,边权为最小割,然后会将整个集合分为两个小集合,递归下去不断构建即可。构建复杂度为 。
性质
的最小割等于 在最小割树上边的最小值。
下文定义 为 的最小割。
性质 1
对于边 , 分别属于该边两侧的子树,则有 。
如果不成立,那么割 的代价割不掉 , 联通, 联通,于是 没有割掉。
性质 2
对于任意不同的 ,
假设最小的是 ,假设 在割掉 之后和 联通,那么由性质 1,,有因为假设 最小,于是 。
于是最小值至少有两个,下面就很好说明了。
性质 2 推论
对于 ,
综合"性质 1"[13] 和 "性质 2 推论"[14],可得
的最小割等于 在最小割树上边的最小值。
↩︎int get(int x, int y) { F :: reset(); F :: setst(x, y); rep(i, 1, m) F :: link(u[i], v[i], w[i]), F :: link(v[i], u[i], w[i]); return F :: runit(); } void build(int l, int r) { if(l == r) return; int x = p[l], y = p[r], w = get(x, y); G[x].eb(y, w); G[y].eb(x, w); top = 0, top2 = l; rep(i, l, r) if(!F :: d[p[i]]) q[++top] = p[i]; else p[top2++] = p[i]; int cur = r; while(top) p[cur--] = q[top--]; build(l, cur); build(cur + 1, r); }
CF343E Pumping Stations
个点, 条边的带权无向图。
你需要构造一个排列,收益为 。
表示图中 为源点, 为汇点的最小割。
求最大的收益,并输出方案。
首先建立最小割树,然后定义两点之间距离为其在最小割树上边权的 值,问题就是:求一个排列,使得其路径之和最长。
因为是 值作为路径,因此,答案的上界就是所有边权之和,我们可以考虑构造一种方案使得答案到达上界:
- 树分治,然后每次在这个树中找到边权最小的边,对于 在树上的路径,如果跨过该边,那么距离就是该边权值了。
- 因为该权值最小,我们要先尽量不经过这条边,分别把分出的两个集合走完,最后在跨过这条边,刚好经过一次。
- 因此最后的答案是可以达到所有边权之和这一上界的。
[POI2009] LYZ-Ice Skates
滑冰俱乐部初始有 号码溜冰鞋各 双,已知 号脚的人可以穿 号码的鞋子。现在有 次操作,每次两个数 ,表示 号脚的人来了 个, 为负表示离开。对于每次操作,输出溜冰鞋是否足够。
由 Hall 定理,记前缀和为 ,那么我们就是要:
这个非常好办,拆项然后线段树维护。 ↩︎
[CERC2016]二分毯 Bipartite Blanket
在二分图中,所有点被划分成了两个不相交的集合 和 ,每条边都恰好连接着某个 和某个 。一个匹配是一个边集,满足没有任何两条边有相同的端点。我们称一个匹配 覆盖了点集 当且仅当 中的每个点都是 中至少一条边的端点。
给定一个二分图,每个点有一个正整数权值。定义一个点集的权值为其中所有点的权值之和。
给定一个参数 ,请统计有多少点集 ,满足 的权值不小于 ,且 被至少一个匹配 覆盖。
,,
首先有一个结论:
- 在二分图中,如果 ,且各自有匹配覆盖 ,那么 也是有匹配覆盖的。
考虑将覆盖 的匹配拿出来,摆到一起:
于是会形成若干个环和链,分类讨论环和链的情况就行了,长这样:
剩下的就是对于左边集合和右边集合分别状压 DP check 一下,然后双指针即可。 ↩︎
[SNOI2019] 通信
个排成一列的哨站要进行通信。第 个哨站的频段为 。
每个哨站 需要选择以下二者之一:
- 直接连接到控制中心,代价为 ;
- 连接到前面的某个哨站 (),代价为 。每个哨站只能被后面的至多一个哨站连接。
请你求出最小可能的代价和。
,
考虑暴力网络流,我们把 拆为两个点 ,如果 流向 则代表和控制中心连接,如果 连向 那么就代表是连接 ,然后 在连向 ,代表把最多向后连的限制让给 。
于是这么建图:
暴力建边很可能 T 掉,于是考虑优化。
我们可以用 CDQ + 归并处理。 ↩︎
性质 1
对于边 , 分别属于该边两侧的子树,则有 。
性质 2 推论
对于 ,
综合"性质 1"[13:1] 和 "性质 2 推论"[14:1],可得
的最小割等于 在最小割树上边的最小值。
↩︎ ↩︎int get(int x, int y) { F :: reset(); F :: setst(x, y); rep(i, 1, m) F :: link(u[i], v[i], w[i]), F :: link(v[i], u[i], w[i]); return F :: runit(); } void build(int l, int r) { if(l == r) return; int x = p[l], y = p[r], w = get(x, y); G[x].eb(y, w); G[y].eb(x, w); top = 0, top2 = l; rep(i, l, r) if(!F :: d[p[i]]) q[++top] = p[i]; else p[top2++] = p[i]; int cur = r; while(top) p[cur--] = q[top--]; build(l, cur); build(cur + 1, r); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现