一类图论相关的状压 DP 题的常见解法
在这里我们要讨论的是和图的连通性、强连通性、双连通性相关的一类状压 dp。
本文不涉及集合幂级数 / ,因为我不会!
这是两道例题:
[GYM 102759C] Economic One-way Roads (最小生成强连通子图)
题意:给定一张无向图和将其上每条边定向的代价,求使图强连通的代价最小的定向方法。
[UOJ 37] 主旋律 (生成强连通子图计数)
题意:给定一张有向图,对它的强连通生成子图(包含全部顶点和边的一个子集)计数。
使用状压 dp 求解此类题目时,需要找到一种问题对象的构造方法(在下文中有更具体的解释)。一般来说,在这类问题中,计数要比最优化更加困难,因为最优化只需要考虑到所有方案,然而计数需要使所有方案都被算入恰好一次。通常最优化题可以直接 dp,然而计数题需要套一层容斥。当然,也并不完全是这样,因为计数问题满足可减性,而最优化问题不满足可减性,因此有时计数可以被广义的容斥技巧优化至更低的复杂度。
连通图
裸的 “最小权生成连通子图” 实际上就是最小生成树是 P 的;裸的 “生成连通子图计数” 是所有生成子图的集合幂级数 ,或熟知的容斥状压 dp:枚举 所在的连通块。这里给两个稍微带点技巧的例子:
最优化
[TC SRM7951C] DiscountedShortestPaths
题意:给一张无向图和一个序列,求每对点之间的最短路之和,这里路径长度定义为经过的边的边权序列经过最优的方式重排后对一个序列(当两序列不等长时可以补零)对位减后求和的结果。
特殊的时空限制:4s / 48MB
显然我们会把两个序列都排序后再对位减。因为这里的路径长度定义和排序后的边权序列相关,因此不得不状压 dp。不过,连通性的信息很难用 的压位信息来表示。我们可以考虑放宽计算的边序列的条件,注意到当边序列使得仅有某两点度数为 时这两点一定可以连通,那么可以考虑对这样的边序列求最优化,此时会把一条链加上若干环的情形多算,但这些情况一定不会更优,因此不影响答案。设计 表示用了 条边使 内的点度数是奇数。可以在 时间和 空间内完成。
但是存在比这更优秀的做法。我们有结论:最优路径一定是其上点集的一个最小生成树。因为如果不是,则存在一条环边可以替换一条树边,这样替换后连通性不变且新的边权序列相较于原来的边权序列每一项都更小,一定更优。这样我们可以枚举每个点集做一遍最小生成树,时间复杂度 ,空间复杂度 。
计数
[?] 生成树
题意:给一张图,对每个 求其恰好有 条边的连通生成子图数量。
我们首先在状压 dp 中加一维表示边数,那么有转移
实际上 看成关于 的生成函数 项系数的话,那么我们对 这个系数序列对应的 GF 的操作是:
- 加上
- 加上
不妨考虑基变换:用 替代 ,即记录 满足:
那么我们对 的操作是:将 位移 位,加到 上;将 加上 。这样我们就用基变换去掉了内层的背包。复杂度是 。
强连通图
最优化
[GYM 102759C] Economic One-way Roads
所有的强连通图都可以由如下方式生成:在一张强连通图上选择两个顶点 ,将 到 的一条路径加入这张强连通图中。其充分性是显然的:这条路径上的每个点都可以通过 到达新强连通图的每个点,且由 被到达。
在这道题中我们要特别注意,当 相等的时候这个路径上不能没有其它点,也不能只有一个其它点。如果是这样的话,路径形如 ,一条边会被用两次。
考虑一个 dp: 表示 内的点形成一张强连通图,定向的最小代价。 表示原先的强连通图和一条考虑了一半的路径的点集的并是 ,且这条考虑了一半的路径准备在 结束, 是目前最后一个加入的节点的定向的最小代价。转移是这样的:
- 中选择两个点 就可以转移到 ;再考虑 中选择的 满足 的情况,额外枚举路径上 之后的一个点 和 之前的一个点 满足 ,转移到 。
- 选择一个 的邻居 就可转移到 , 可以转移到 。
由于 互相转移时 并不是严格单调,这里有一个转移顺序的问题,对于每个 应当先用 转移到 ,再用 更新 ,再考虑 中的互相转移。
这样做还有一个问题,就是我们只考虑了在强连通图上的边,而没有考虑到不在强连通图上的边定向的代价。这个问题很好解决,只需要先把每条边都定向为代价更小的一个方向,然后在钦定一条边的方向时考虑是否和一开始定的方向不同。
复杂度是
计数
[UOJ 37] 主旋律 (生成强连通图计数)
很明显,刚才的构造方法不能用在这道题上面,因为每个强连通图会被算到不止一次。
考虑非强连通图和强连通图之间的容斥关系。这里,直接对强连通分量个数容斥是困难的,因为我们很难构造每个强连通分量加入的顺序,也很难记录连通性信息。
我们注意到非强连通图缩点之后的 DAG 满足入度为 的点不是全集,所以考虑对这样的图计数。我们需要钦定入度为 的点。如果一张图上入度为 的强连通分量为某种方案(即一种方案对应了一个强连通分量集合,每个强连通分量都包含了原图上的某个点集),那么钦定这个方案的强连通分量的每个子集入度为 ,都会把这个方案算到。显然,将容斥系数设为 就可以把每种方案都算到一次。
考虑两个 dp: 表示点集 的强连通生成子图数量。 表示把 划分成 个强连通分量的方案的 之和。转移如下:
-
,这里 表示 指向 的边数,可以用 地算出。
-
复杂度是 ,实际上通过适当的预处理可以做到 。
DAG
计数
[CometOJ 1581] [Contest #11]F-arewell
题意:给定一张图的每条边分别有 的概率取正向、反向或消失,问最终图成为 DAG 的概率。
实际上在刚才讨论强连通图计数的时候已经涉及了 DAG 计数的核心思想:按层枚举 DAG 入度为 的点。假设枚举了入度为 的子集为 ,原集合为 ,那么转移的系数是 。令 为 的答案,那么有转移:
很明显这是一个集合幂级数的子集卷积,可以用 FMT 优化到 。注意,如果给的图是有向图,即贡献关于 和 不独立,那么就很难用 FMT 优化。
最优化
单纯的生成 DAG 最优化可以直接对拓扑序状压 dp,这就是一个会把每个 DAG 算多次的构造。
点 / 边双连通图
最优化
[CF 1155F] Delivery Oligopoly (最小生成边双)
题意:给一张图,试保留最少的边,使得图是边双。
可以直接借鉴强连通图的办法,在一个边双上不停贴链。要注意贴上去的链至少要包含一个其它点。
对于点双的情况,其实是类似的,只是贴链的时候起点终点不能是同一个。
计数
事实上点 / 边双连通生成子图都是集合幂级数 / 的经典应用(见 https://loj.ac/d/2668 )。如果不涉及这一知识点的话,只能通过暴力子集枚举做到 的复杂度;但是很可惜,由于圆方树的结构比较复杂,可能要暴力对圆方树加根 dp,从而有着更高的复杂度。
[HDU 4997] Biconnected
题意:给一张图,问有多少种加边的方法,使得图是边双。
同样可以借鉴强连通图计数的方法。用连通图数量减去不是边双的连通图数量,连通图数量显然可以容斥 所在的连通块。而不是边双的图必定缩点后是一棵边双树,且其叶节点不是全集(可以直接套用 DAG 容斥入度为 的点的方法计数),除非边双树只有一条树边连接两个边双——这种情况只要加回来就行了。
Bonus:
[GYM 102331C] Counting Cactus (生成边仙人掌计数)
题意:给一张图(无重边自环),求有多少个边的子集使得没有任何一条边在两个环中。
很明显缩点之后是树形结构的,也可以用集合幂级数 ln / exp 的方法做。这里介绍一个 的 dp。
令 表示以 为根,以 为点集的仙人掌个数。我们考虑仙人掌的结构,点 有可能在很多环当中,还有一些不成环的出边,而这些环 / 边是不交的。并且,删去这些环 / 边之后,整张图会形成若干连通块——换言之,每个环 / 边底下都拖着一个点集。我们枚举 所在的点集,则这部分的结构就是一个环 / 边拖着一个点集,且这个环 / 边包含了 ,而 除了这个环没有任何邻居;而剩下的部分则仍然是一个仙人掌,只是点集变成了原来的一个子集。
令 表示以 为根的 “环 / 边 + 点集” 的结构的数量。如果 所在的是一个环,不妨枚举 在环上的邻边指向的是点 ,把这条边断开之后这个结构就变成了一条链,链上每个点除了 之外底下都挂了一个点仙人掌。
令 表示 “ 到 的一条链,链上每个点除了 之外底下都挂一个点仙人掌” 的结构的数量。每次枚举 的上一个点,以及 中有哪些点是挂在 下面,就可以从 转移而来。
这样做会有一个问题,即在 中每个环都被正向和反向算了两次;但是如果直接除以 ,又会把 到 只通过一条边相连的情况多除掉,所以要把这种情况加回来。这种情况的方案数正是 。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!