经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C 语言 » 查看文章
关于基环树的一切
来源:cnblogs  作者:Sugar_Cube  时间:2024/4/8 8:54:36  对本文有异议

观前须知

笔者的博客主页

声明

本文使用 CC BY-NC-SA 4.0 许可

本文为笔者在 OI 学习中的复习向学习笔记。
部分内容会比较简略。
如有好的习题会不断补充。

知识简介

定义

基环树是一个有 \(n\) 个点 \(n\) 条边的连通图。
因为\(n\) 个点 \(n-1\) 条边。
所以基环树可以看作是加了一条边的树。
那么也就是加了个环的树
注意:题目中给 \(n\)\(n\) 边时可能是基环树,也可能是基环树森林。
后一种情况分连通分量分别做即可。

如图:

基环树

拓扑排序找环

无向图:
不断地删除 1 度点,直到留下的全部都是 2 度点,即为环。

有向图:
同上,只不过每次删入度为 0 的点。

DFS找环

无向图:
走的时候记 dfn 和 fa,
遇到遍历过且 dfn 大的点(防止重复计算),
就不断跳 fa 并记录。

代码:

  1. void Dfs(int u) {
  2. dfn[u] = ++Time;
  3. for (int i = head[u]; i; i = e[i].nxt) {
  4. int v = e[i].v;
  5. if (v == fa[u]) continue;
  6. if (!dfn[v]) { fa[v] = u, Dfs(v); }
  7. else {
  8. if (dfn[v] < dfn[u]) continue;
  9. loop[++cnt] = v;
  10. while (v != u) loop[++cnt] = v = fa[v];
  11. }
  12. }
  13. }

有向图:
如果边指向叶子可以反过来。
边指向根的树只需要不断向上跳 fa,同时打标记,
直到跳到树的根后,再跳到的点已经打过标记了,那么就找到环了。
(如果要树型DP的话可以再建个反向图,就不用建双向图了)

代码:

  1. while (!vis[x]) vis[x] = true, x = fa[x];
  2. int v = x;
  3. while (v != x) loop[++cnt] = v = fa[v];

基环树常见问题处理方式

把环断开,发现图变成了若干个森林
那么可以把基环树看作用一个环连接着的若干棵树。
这时候就可以先断环,然后再树型DP了。
特别地,有些题涉及到树之间经过环的转移。
这类问题可以分类讨论成不经过环的和经过环的分别处理。
由于有环的出现,破环为链也比较常用。

习题

Luogu P2607 【ZJOI2008】 骑士

首先这个东西显然可以树型DP做。
但是这里是个基环树森林。
发现对于环的任意两个相邻点只能二选一或都不选。
那么任取环上的两个点分别做树型dp取 \(\max(f_{u_1,0},f_{u_2,0})\),然后对每个基环树求和即可。

原文链接:https://www.cnblogs.com/Sugar-Cube/p/18119741

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号