【不定期更新】图论100问
最大半连通子图
首先考虑一个 scc ,显然,scc 中任意两个节点满足半联通。缩点后,原图就变成一个 DAG。
下证半联通子图的必要条件是存在原点 u,使得 u 到子图中任意一个其他节点都存在有向路径。
假设对于 u,v,u 不能到 v 而 v 不能到 u,那么将 v 作为新的节点,继续重复上述过程,一定有一个节点 w ,满足到子图中任意一个其他节点都存在有向路径。
得证。
而且容易发现任意半联通子图都有且仅有一个源点 w。
这启示我们用拓扑排序来解决这个问题。
设 f_x 表示以 x 为根,满足半联通的子树的大小。
显然链是满足条件的。对于子树=2的情况,手玩了几组发现可以连接成单链的情况,自然>=3的情况也可以接成单链。
综上所述,我们只需要在缩完点的图中跑 DAG,然后找到最长链的情况即可。
注意到这里的 G’ 由点集 V’ 决定。由于是求方案数,所以必须考虑判重的问题。
注意到原图是没有重边的。然而缩点后可能出现重边,但是两种方案的点集是一样的,只不过选择的连接边不同而已。
所以用 map 判一下重边即可。(这里我也没有注意到,是被人hack后发现的)
对于图的连通性问题,我们通常要考虑以下几点:
- 图的连通性
- 重边,自环(对于 dcc 算法重边是有影响的,染色法不能出现自环,缩点算法后是可能出现重边的,要注意判重)
- 简单环,简单路径的定义,注意无向图的简单环不能经过重复的边,大小至少为2,如 1 2 2 1 是合法的,而 1 2 是不合法的,因为同一条边经过了两次
- 有的题目重边可以忽略,但有的题目重边会影响答案,如图论计数等
- 自环一般影响不大,但是要注意自环算简单环。简单路径是没有经过相同点的迹。简单环则是起点和终点相同的简单路径。简单环一定是简单路径。回路是起点和重点相同的迹,也就是说可以经过相同点。
- 注意到上述概念都涉及到相同边不能经过两次。这一点在有向图中应该问题不大,因为一旦经过相同点两次,则说明该路径已经构成简单路径和简单环,当然也构成回路。在无向图中这样要求是很有必要的。
CF962F Simple Cycles Edges
You are given an undirected graph, consisting of n n vertices and m m edges. The graph does not necessarily connected. Guaranteed, that the graph does not contain multiple edges (more than one edges between a pair of vertices) or loops (edges from a vertex to itself).
A cycle in a graph is called a simple, if it contains each own vertex exactly once. So simple cycle doesn’t allow to visit a vertex more than once in a cycle.
Determine the edges, which belong to exactly on one simple cycle.
题意大概是说,给定一个无自环和无重边的无向图,求哪些边有且仅被包含在一个简单环中。
第一感是用 DFS 来解决。
分类讨论:
-
若 (u,v) 是树边,则只需树上差分统计经过这条边的回环即可。注意到一个复杂的简单环是可以由两个简单环拼成的,所以不能只考虑被一个简单环覆盖的条件。
-
首先,它一定在一个环中。其次,环之间不能有交叉。对于非树边的判断其实是类似的,如果这个环和其他环无交叉,那么这条连接边也是满足条件的。
-
注意到一个简单环里的节点是有联系的。考虑用 c_x 来建立这个联系。
-
首先,判断一条边是否只经过一个简单环,然后,考虑该环中的其他边是否都不被其他简单环经过。
-
经过观察,我们发现它的含义其实就是 sum_v-sum_u=dep_v-dep_u ,此时该环包含的所有点都满足条件。
至于具体实现,这里用的是二次树上差分。
我用的是暴力跳链,严谨的话应该用树链剖分。
事实上本题可以转化为求点数等于边数的 vcc。然而我没有想到
支配树
用 DFS 树来理解它。分为三种边:前向边,横叉边和返祖边。
主要提一下半支配点 semi(x) 的求法:
-
用带权并查集维护由前向边和横叉边组成的 dfn(w \in edge) \req dfn(u) 且 dfn(v->u) 最小的点的序号
-
anc_min(v) 维护的是 v 到根节点的集合,可能通过横叉边到达非直系节点,有前提 dfn(v) \leq dfn(w),非直系节点的 semi(w) 也算,但是显然只会贡献一次,所以令 anc(x)=fa(x) 是在寻找祖先集合的贡献,这部分贡献应该给其子树的所有节点,如果令 anc(x)=son(x) 的话,其前叉边的贡献已经不会变了,而返祖边可能有贡献,所以把当前还未处理到的祖先节点看做并查集所表示的集合。至于前叉边的贡献在求 semi(u) 的过程中就可以算出来了。
-
按时间戳从大到小处理。遍历反向边 (u,v),如果 v 是 u 的祖先,则 res=min(res,dfn[semi[y]]);
-
如果 v 不是 u 的祖先,若 (u,v) 是前向边,那么询问从 v 出发的横叉边 (之前已经处理过了)以及并查集所代表的 dfn(w) \req dfn(u) 的祖先集合即可。
-
若 (u,v) 是横叉边,同样 find 压缩路径,这一部分就把横叉边+返祖边都压缩了。
然后将所有 (semi(x),x) 连边。这里用了等效替代的思想,即通过树边到 x 与所有通过 semi(x) 的半支配路径两种情况。注意到转化后图变成了 DAG,可以 拓扑排序 + LCA 解决。
同时注意到,每个节点最多只有 2 条入边。(这个 hf 没有提及,但是我认为是一个正确的性质)
时间复杂度 O((n+m)logn+(n+m)a(n)) 。
我们这里有 O((n+m)a(n)) 的更优算法:
-
如果z的semi和x的一样,则idom[x]=semi[x]。
-
否则 idom[x]=idom[z]。
枚举 x=semi[y],此时 刚好将时间戳在 [1,dfn[x]-1] 的点处理完, find(y) 压缩路径,此时求到的 semi[anc_min[y]] 就是所谓的 z。这步是时机,因为如果并查集连到 x 以上的节点,就不满足 z 在 [semi[y],y] 的路径上了。
矿场搭建
图不是联通的,所以我们依次考虑若干联通块。
首先考虑割点。
-
如果一个联通块不存在割点,那么至少需要建立两个救援点,方案数为 n ( n − 1 ) / 2 n(n-1)/2 n(n−1)/2
-
如果一个联通块存在多个割点,不妨把它转化成 vcc 缩点后的树。把每个割点都作为新图中的节点,并在每个个点与包含它的所有 vcc 连边
-
此时我们发现如果一个 vcc 所包含的全局的割点为 1(即新图中的叶子节点),那么我们一定在除了割点的任意一个点建立救援点,同时发现建一个救援点是最优的。
-
然后我们发现任意删除图中的一个割点,其余节点都存在至少一条到叶节点的路径。而且树的叶子节点至少有2个,即使去掉一个也不会使所有救援点都消失,所以是不矛盾的。
然后注意求 vcc 是将 y 节点以前的弹出,而不是将 x 节点以前的弹出,否则就会弹出一些兄弟节点(这些节点原本是不存在割点的),此时 x 就成为割点了。
软件安装
还是那个问题:注意缩点后入度为0和重边的情况。重边意味着会重复计算同一个子树。不过本题保证没有重边。
注意到这是一个基环树。缩点后跑树上背包即可。注意必须从 0 连向缩点后入度为0的节点。
__EOF__

本文链接:https://www.cnblogs.com/cqbzly/p/17530362.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」