Tarjan-vDCC,点双连通分量,点双连通分量缩点

前言

双连通分量是无向图中的一个概念,它是指无向图中的一个极大子图,根据限制条件可以分为边双连通分量和点双连通分量,欲了解双连通分量需先了解Tarjan算法,以及割点割边的概念及求解。本篇博客介绍点双连通分量的相关内容。


前置知识

学习点双连通分量前,你需要先了解:

关于Tarjan:SCC-Tarjan算法,强连通分量算法,从dfs到Tarjan详解-CSDN博客
关于缩点:SCC-Tarjan,缩点问题-CSDN博客
关于割点:Tarjan-割点问题-CSDN博客
关于割边:Tarjan-割边问题-CSDN博客


点双连通分量的定义

在无向图中,存在一个极大子图,其中任意两个顶点之间连通,并且删除任意一点该子图仍然是连通的,我们称该极大子图为点双连通分量(vertex Double Connected Components,vDCC)

推论

  • 无向图中极大的不包含割点的连通分量被称为点双连通分量(vertex Double Connected Components,vDCC)

  • 一个割点存在于至少两个双连通分量之中

如下图中1、5为割点,{1,2,3,4}, {1,5},{5,6}, {5,7,8}均为vDcc

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=C%3A%5CUsers%5C在这里插入图片描述
%E5%8F%B2%E9%91%AB%E9%98%B3%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20231222195235335.png&pos_id=img-r6Pf4tFh-1703247458562)

Tarjan算法求解vDcc

我们回顾一下Tarjan算法涉及到的概念:

搜索树

我们dfs对图遍历,保证每个点只访问一次,访问过的节点和边构成一棵有向树,我们称之为搜索树

强连通分量的根

如果节点x是某个强连通分量在搜索树中遇到的第一个节点,那么这个强连通分量的其余节点肯定是在搜索树中以x为根的子树中。节点x被称为这个强连通分量的根

时间戳

我们用数组dfn[]来保存节点第一次访问时间,dfn[x]即节点x第一次访问的时间戳

追溯值

数组low[]来记录每个节点出发能够访问的最早时间戳,记low[x]节点x出发能够访问的最早时间戳,即追溯值


算法原理

仍然是基于Tarjan算法进行求解,其实就是Tarjan算法求解割点和强连通分量的结合。

我们Tarjan在有向图求SCC中,通过栈保存连通分量的节点,又通过时间戳和追溯值是否相等来找到强连通分量的根从而从栈中取出节点
而求解割点时,我们对于low值更新是不允许越过父节点来更新low值的,即我们else代码段中的low[x] = min(low[x], dfn[y]);

那么我们如何来记录点双连通分量呢?

点双连通分量的记录

和求解SCC,eDCC一样,借助栈来保存节点以及取出连通分量中的点。不过与前两者不同的是,前者在完成子节点遍历后根据时间戳和追溯值判断根来取出连通分量中的节点,而vDCC要在出现一个子节点y满足low[y] >= dfn[x]时就进行vDCC的记录。为什么呢?

如下图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1为割点,但是点双连通分量为{1,4,5}和{1,2,3},也就是说对于一个割点它可以是多个环的环顶,所以遍历完一个环就要把这个环和割点本身记录为一个点双连通分量。

孤立点和自环的特判

孤立点

我们的图中如果有孤立点的话,其自身就是一个vDCC,所以对于孤立点我们直接给他开个单间,放到一个vDCC中,不过出不出栈无所谓,因为孤立点不影响前面的vDCC和后面的vDCC。

自环

如果是含有多个点的vDCC的话我们不用特殊处理,自然会归到相应的vDCC,但如果是孤立自环也就是说孤立点的自环的话,我们需要特判,很简单,我们tarjan求割点要记录child,对于孤立点自环child自然为0而且low[x] == dfn[x],以此特判即可,后面代码会具体实现。


算法流程
  • 给x打时间戳,入栈
  • 如果是孤立点,直接开单间,返回
  • 否则遍历子节点y,记录child,
  • low[y] >= dfn[x],child++,根据情况记录割点,然后记录vDCC
  • 离开函数时特判孤立点自环
代码实现

仍然是使用链式前向星存图,关于链式前向星,详见:一种实用的边的存储结构–链式前向星-CSDN博客

#define N 500010
#define M 4000010
struct edge
{int v, nxt;
} edges[M];
int head[N], idx = 0;
void addedge(int u, int v)
{edges[idx] = {v, head[u]};head[u] = idx++;
}
int n, m, dfn[N], low[N], st[N], tot = 0, cnt = 0, top = 0, root;
bitset<N> cut;
vector<int> vdcc[N];
void tarjan(int x)
{low[x] = dfn[x] = ++tot;st[top++] = x;// 孤立点if (head[x] == -1){vdcc[++cnt].emplace_back(x);return;}int child = 0, y;for (int j = head[x]; ~j; j = edges[j].nxt){y = edges[j].v;if (!dfn[y]){tarjan(y);low[x] = min(low[x], low[y]);if (low[y] >= dfn[x]){child++;if (x != root || child > 1)cut[x] = 1;cnt++;int z;do{z = st[--top];vdcc[cnt].emplace_back(z);} while (z != y);vdcc[cnt].emplace_back(x);}}elselow[x] = min(low[x], dfn[y]);}// 孤立点自环if (!child && dfn[x] == low[x])vdcc[++cnt].emplace_back(x);
}

vDcc缩点问题

vDCC缩点相较于SCC缩点和eDCC缩点也有所不同,因为涉及到了割点的分裂,所以每个vDCC缩点后是跟割点进行相连,vDCC缩点后也会得到一棵树或森林。

代码实现如下:g为缩点图的邻接表存储

//vector<int> vdcc[N], g[N];int num = cnt;
for (int i = 1; i <= n; i++)if (cut[i])id[i] = ++num;
for (int i = 1; i <= cnt; i++)for (auto x : vdcc[i]){if (cut[x]){g[i].emplace_back(id[x]);g[id[x]].emplace_back(i);}}

OJ练习

P8435 【模板】点双连通分量 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/293473.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis取最近10条记录

有时候我们有这样的需求&#xff0c;就是取最近10条数据展示&#xff0c;这些数据不需要存数据库&#xff0c;只用于暂时最近的10条&#xff0c;就没必要在用到Mysql类似的数据库&#xff0c;只需要用redis即可&#xff0c;这样既方便也快&#xff01; 具体取最近10条的方法&a…

千帆 AppBuilder 初体验,不仅解决解决了我筛选简历的痛苦,更是让提效10倍!

文章目录 &#x1f31f; 前言&#x1f31f; 什么是百度智能云千帆 AppBuilder&#x1f31f; 百度智能云千帆 AppBuilder 初体验&#x1f31f; 利用千帆AppBuilder搭建简历小助手&#x1f31f; 让人眼前一亮的神兵利器 - 超级助理 &#x1f31f; 前言 前两天朋友 三掌柜 去北京…

如何搭建Web自动化测试框架?

在程序员的世界中&#xff0c;一切重复性的工作&#xff0c;都应该通过程序自动执行。「自动化测试」就是一个最好的例子。 随着互联网应用开发周期越来越短&#xff0c;迭代速度越来越快&#xff0c;只会点点点&#xff0c;不懂开发的手工测试&#xff0c;已经无法满足如今的…

【计算机系统结构实验】实验5 多核编程(OpenMP编程)

5.1 实验目的 加深对多核处理器架构的理解&#xff1b; 掌握使用OpenMP进行多线程编程的基本方法&#xff1b; 学习Windows和OpenEuler环境下多核编程的过程和time命令&#xff1b; 5.2 实验平台 需要多核处理器的计算机和微软编程工具Visual Studio 2012。Taishan服务器&…

macOS 开发 - MASShortcut

文章目录 关于 MASShortcut项目结构 快速使用源码学习检测是否有热键冲突处理 Event macOS 开发交流 秋秋群&#xff1a;644096295&#xff0c;V : ez-code 关于 MASShortcut MASShortcut 是一款快捷键管理工具&#xff0c;替代和兼容 ShortcutRecorder github : https://git…

【万能技巧】IP知识速通与小技巧~

本文目录 前言一、网络代理IP简介二、IPIDEA 优势2.1 多种类型IP代理2.2 海量纯净代理池2.3 稳定高效数据收集架构 三、IP实操小Tips3.1 查看本地网络IP3.2 使用浏览器IP3.3 使用IPIDEA进行爬虫实操 前言 各位友友&#xff0c;大家好&#xff0c;马上就到2024年了&#xff0c;…

一款外置MOS开关降压型 LED 恒流控制器应用方案

一、基本概述 TX6121 是一款高效率、高精度的降压型大功率 LED 恒流驱动控制器芯片。芯片采用固定关断时间的峰值电流控制方式&#xff0c;关断时间可通过外部电容进行调节&#xff0c;工作频率可根据用户要求而改变。 通过调节外置的电流采样电阻&#xff0c;能控制高亮度 LE…

引领汽车营销新趋势,3DCAT实时云渲染助力汽车三维可视化

当前&#xff0c;汽车产业发展正从电动化的上半场&#xff0c;向智能化的下半场迈进。除了车机技术体验的智能化之外&#xff0c;观车体验的智能化也不容忽视。 这是因为&#xff0c;随着数字化、智能化、个性化的趋势&#xff0c;消费者对汽车的需求和期待也越来越高&#xf…

【华为鸿蒙系统学习】- HarmonyOS4.0之App项目开发|自学篇

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 创建鸿蒙第一个App项目 项目创建 工程目录区 预览区 运行Hello World 基本工程目录 ws:工…

Python教你如何让代码摆脱死循环的困扰!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在编写Python代码时&#xff0c;无限循环是一个常见的问题&#xff0c;可能导致程序陷入死循环&#xff0c;使得代码无法正常执行。这篇博客将介绍一些方法&#xff0c;帮助大家防止和处理无限循环&#xff0c;确…

蓝桥杯2019年10月青少组Python程序设计省赛真题

1:有n个人围成一个圈,按顺序排好号然后从第一个人开始报数(从1到3报数),报到3的人退出圈子,然后继续从1到3报数,直到最后留下一个人游戏结束,问最后留下的是原来第几号输人描迹:输人一个正整数n 输出描迹:输出最后留下的是原来的第几号 [样例输人] [样例输出] 2: 3、 […

「C/C++ 01」 深拷贝和浅拷贝

目录 一、概念 1. 浅拷贝 2. 深拷贝 3. 深浅拷贝问题 4. 总结 二、在C的类中实现深拷贝 1. 拷贝构造函数 中实现深拷贝 a. 自己开辟一个新空间&#xff0c;然后将内容拷贝到新空间 b. 借助构造函数来实现深拷贝 2. operator 中实现深拷贝 a. 自己开辟一个新空间&#xff0c;…