图上构造问题技巧整理
在 CF 或者某些省的省选题中,有时你会遇到这样的问题:给你一张图和两个看似不相关的问题(如求某个大小 \(\ge X\) 的链/独立集/环/导出子图满足某个条件的点集),让你选择一个完成,保证有解。
这种题目一般对思维要求比较高,不过如果仔细琢磨,那么解决这种题还是有迹可循的。
1. CF1198C Matching vs Independent Set
这虽然只是道难度 *2000 的 D1C,但仔细研究还是能发现些什么的(以小见大,yyq 附体)
首先题目这个 \(3n\) 就给得比较诡异,一个 observation 是大小为 \(n\) 的匹配恰好包含 \(2n\) 个点,一个大小为 \(n\) 的独立集恰好包含 \(n\) 个点,它们加起来刚好是 \(3n\)。
因此考虑这样一个 algorithm
:找出原图的一个极大匹配——对于每条边如果它们都没有访问过就将它们加入匹配中并设为访问过。那么显然选出的边组成一个匹配,剩余的点组成一个独立集。那么如果匹配中边的大小 \(k\ge n\) 就输出这个匹配中 \(n\) 条边,否则一定有 \(3n-2k>n\),输出这个独立集中任意 \(n\) 个点即可。
2. CF1325F Ehab's Last Theorem
DFS 树真是个好东西(大雾)
首先我们考虑求出原树的 DFS 树,即从某个点开始 DFS 经过的边的集合构成的树,那么 DFS 树的一个性质是不存在横叉边(否则假设横叉边为 \((u,v)\),那么 \((u,v)\) 为横叉边意味着在从 \(u\) 开始 DFS 下去的过程中不会访问到 \(v\),只有当 \(u\) 回溯到 \(\text{LCA}(u,v)\) 时才访问到了 \(v\),这显然是有悖于 DFS 的过程的),也就是说 DFS 树上非树边的两个端点一定是祖先关系。
有了这个性质之后我们来看这道题,我们记 \(lim=\lceil\sqrt{n}\rceil\),那么如果存在一条非树边,其两个端点深度之差 \(\ge lim-1\),那么这条边与这两点在 DFS 树上的路径就构成了一个长度 \(\ge lim\) 的环。否则我们按照深度 \(\bmod (lim-1)\) 分成 \(lim-1\) 类,由于非树边之间的深度差 \(<lim-1\),故同类节点中一定没有边相连,而根据抽屉原理一定存在一类,节点个数 \(\ge\lceil\dfrac{n}{lim-1}\rceil\ge lim\),输出这一类中任意 \(lim\) 个节点即可。
3. CF1391E Pairs of Pairs
DFS 树的应用 *2
还是考虑建出原图的 DFS 树,记 \(u\) 为深度最大的点,\(lim=\lceil\dfrac{n}{2}\rceil\),如果 \(dep_u\ge lim-1\) 那输出 \(u\) 到根节点的路径即可,否则记 \(S_d\) 为所有深度为 \(d\) 的点组成的集合,那么对于所有 \(d\),我们将 \(S_d\) 的点两两配对输出即可,落单的点就直接扔了,由于 DFS 树上不存在横叉边,因此任意两对的四个节点中最多存在两条边,符合题目要求,而这样总共参与配对的节点数为 \(n-\sum|S_d|\bmod 2\),由于 \(d<lim-1\),\(\sum|S_d|\bmod 2\le lim-1\),总参与配对的节点数也就 \(\ge n-(lim-1)\ge lim\)。
4. CF1439B Graph Subset Problem
卡常妹妹题,爬~
不难注意到度数 \(<k-1\) 的点对两种答案都没有贡献,因此考虑维护一个 std::set
\(S\) 将所有度数 \(\le k-1\) 的点压入 set
中,每次取出 \(S\) 中度数最小的点 \(x\),遍历一遍 \(x\) 的邻居 \(y\) 并将 \(y\) 的度数 \(-1\),如果 \(y\) 的度数 \(\le k-1\) 就将 \(y\) 压入 set
中,并将 \(x\) 从图中删去,如果 \(x=k-1\) 那么我们还需额外检验所有与 \(x\) 相邻的且没被删去的点集 \(T\) 是否满足 \(T\) 中两两都有边相连,如果是那么 \(T\cup\{x\}\) 就组成了一个大小为 \(k\) 的团,直接输出即可。如此操作下去直至 \(S\) 不为空即可。如果最终图被删空了那答案就是 \(-1\),否则图中所有点度数肯定都是 \(\ge k\) 的,输出图中的点即可。
算下复杂度,瓶颈在于暴力检验 \(T\) 中的边是否有边相连,不难发现只有当 \(\dbinom{k}{2}\le m\) 的时候才需检验这种情况,而如果删到 \(x\) 时 \(x\) 的度数为 \(k-1\),那么一定有 \(x\) 在原图中的度 \(\ge k-1\),这样的点不超过 \(\dfrac{m}{k-1}\) 个,因此总检验次数为 \(\mathcal(\dfrac{x}{k-1})\times\mathcal O(k^2)=\mathcal O(m·k)=\mathcal O(m\sqrt{m})\),再加上检验两点间是否有边的复杂度 \(\mathcal O(\log m)\)(事实上是可以做到 \(\mathcal O(1)\) 的,但是懒得学了/ts),总复杂度 \(m\sqrt{m}\log m\)
所以 \(m\sqrt{m}\log m\) 对于 \(m=10^5\) 为什么只开 1s 时限呢/yiw?CF 为什么出卡常题呢?总之,出题人爪巴(大雾
5. P5361 [SDOI2019]热闹的聚会与尴尬的聚会
终于嗅到省选题的气息了(大雾
首先题目条件可以转化为 \((p+1)(q+1)>n\),那么显然我们要分别最大化 \(p\) 和 \(q\)。
最大化 \(p\) 是容易的,我们考虑维护一个 set
,装有每个点的度和它的编号,每次取出 set
中度数最小的节点并将它删掉,更新相邻节点的度,然后取最小节点的度最大的点作为最终的点集即可。
然鹅最大化 \(q\)……我们伟大的 SDOI 竟出 NPC 问题?!!i 了 i 了
显然这题的数据范围不是让你模拟退火的,因此我们需考虑别的做法。这题的目的是为了让你最大化 \(q\) 吗?是让你找到一个 \(p,q\) 满足 \((p+1)(q+1)>n\)!那出题人为什么要强行搞这么一个二合一呢?显然是因为这两个子任务之间有一定的内在联系啊。
因此我们考虑在最大化 \(p\) 的算法中进行一些魔改。我们从 set
中取出度数最小的节点 \(x\) 之后,直接将其加入最大独立集并删去所有与 \(x\) 相邻的点,然后还是取最小度数最大时刻的图以及最后的独立集作为最终答案,这样就可以完成任务了。
为什么这样做是正确的呢?因为每次我们取出一个点时,删去的点的个数就等于当时该点的度数 \(+1\),而因为 \(p\) 是所有时刻度数最小的点中度数最大的,因此每次取出的点的度数 \(\le p\),每次删去的点的个数也就 \(\le p+1\),删点的轮数也就 \(\ge\lfloor\dfrac{n}{p+1}\rfloor\),又因为我们每删一轮点,就会将恰好一个点加入独立集,因此独立集的大小 \(\ge\lfloor\dfrac{n}{p+1}\rfloor\)
总结
总之,当你在图上见到两个不相干的问题时,要善于把握它们之间的联系,碰到无向图有关的问题时,不妨找出它们的 DFS 树,可能对解题有一些帮助。遇到度数有关的问题时可以将每个点及它的度扔进一个 set
然后每次删掉 set
中度最小的点。
不论怎样还是具体题目具体分析罢(