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);
            }
        }
        else
            low[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)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB ga函数的使用方法

一、ga句法结构 x ga(fitnessfcn,nvars) x ga(fitnessfcn,nvars,A,b) x ga(fitnessfcn,nvars,A,b,Aeq,beq) x ga(fitnessfcn,nvars,A,b,Aeq,beg,IB,UB) x ga(fitnessfcn,nvars,A,b,Aeq,beq,LB,UB,nonlcon) x ga(fitnessfcn,nvars,A,b,Aeq,beq,LB,UB,nonlcon,options) x …

conda环境下更改虚拟环境安装路径

1 引言 在Anaconda中如果没有指定路径,虚拟环境会默认安装在anaconda所安装的目录下,但如果默认环境的磁盘空间不足&#xff0c;无法满足大量安装虚拟环境的需求&#xff0c;此时我们需要更改虚拟环境的安装路径&#xff0c;有以下两种方案&#xff1a; 方案1&#xff1a; 每次…

【AivaAI】做音乐,无人能比它更专业

关于Aiva Aiva AIVA是音乐制作初创公司AIVA Technologies打造的一款人工智能产品。是人工智能领域头款获得国际认证的虚拟作曲家。 Aiva登录 可以选择Google登录&#xff0c;或者其他邮箱登录。 输入用户名&#xff0c;登录完成。 开始制作音乐 在主页选择“创建曲目…

uniapp使用colorUI

colorUI 微动画 | ColorUI 使用文档 1&#xff1a;把colorui里三个文件复制到自己项目中去 App.vue </script> <style> import url(colorui/icon.css); import url(colorui/main.css); import url("colorui/animation.css");-webkit-keyframes show {…

HackTheBox - Medium - Linux - Jupiter

Jupiter Jupiter 是一台中等难度的 Linux 机器&#xff0c;它有一个使用 PostgreSQL 数据库的 Grafana 实例&#xff0c;该数据库在权限上过度扩展&#xff0c;容易受到 SQL 注入的影响&#xff0c;因此容易受到远程代码执行的影响。一旦站稳脚跟&#xff0c;就会注意到一个名…

OPC UA 与PROFINET比较

ROFINET和OPC UA是两种常见的协议&#xff0c;过去这两个协议有两个不同的角色。PROFINET通常用于现场设备和本地控制器之间的实时数据通信。而OPC UA通常用于在本地控制器和更高级别的MES和SCADA系统之间进行通信。 OPC UA 网络架构 PROFINET网络由IO控制器和IO设备组成&…

人工智能_机器学习070_SVM支持向量机_软间隔及优化_硬间隔_衡量间隔软度_引入松弛变量_理解隔离参数---人工智能工作笔记0110

我们继续说,之前说的C是什么意思? 我们在这个软间隔优化中就可以引出C 可以看到之前我们讨论的问题,都是基于样本点的,完全的线性可分的问题,我们称为硬间隔 可以看到这种,一分就可以,分开,简单分割就可以分开的数据,我们称之为硬间隔 但是可以看到上面这种情况,无论怎么分,都…

关于游戏性能优化的技巧

关于游戏性能优化的技巧 游戏性能优化对象池Jobs、Burst、多线程间隔处理定时更新全局广播缓存组件缓存常用数据2D残影优化2D骨骼转GPU动画定时器优化DrawCall合批处理优化碰撞层优化粒子特效 游戏性能优化 好久没有在CSDN上面写文章了&#xff0c;今天突然看到鬼谷工作室技术…

2.3_2 进程互斥的软件实现方法

2.3_2 进程互斥的软件实现方法 #mermaid-svg-MEJSSglXzFe6Q501 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-MEJSSglXzFe6Q501 .error-icon{fill:#552222;}#mermaid-svg-MEJSSglXzFe6Q501 .error-text{fill:#5522…

【微服务】:微服务最佳实践

关键需求 最大限度地提高团队的自主性&#xff1a;创建一个团队可以完成更多工作而不必与其他团队协调的环境。优化开发速度&#xff1a;硬件便宜&#xff0c;人不是。使团队能够轻松快捷地构建强大的服务。关注自动化&#xff1a;人们犯错误。更多的系统操作也意味着更多的事情…

Python多任务编程-09队列Queue

程序中的定义&#xff1a;一种特殊的存储数据的方式&#xff0c;可以实现先存入的数据&#xff0c;先出去 1.程序中的队列Queue FIFO&#xff08;first in first out先进先出&#xff09; import queueq queue.Queue() q.put("22") q.put(500) q.put({"num&q…

nodejs微信小程序+python+PHP医院挂号系统-计算机毕业设计推荐

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

C练习题13答案

单项选择题(本大题共20小题,每小题2分,共40分。在每小题给出的四个备选项中,选出一个正确的答案,并将所选项前的字母填写在答题纸的相应位置上。) 1.结构化程序由三种基本结构组成、三种基本结构组成的算法是(A) A.可以完成任何复杂的任务 B. 只能完成部分复杂的任务 C. 只能完…

MySQL运维实战(1.2)安装部署:使用二进制安装部署

作者&#xff1a;俊达 引言 上一篇我们使用了RPM进行安装部署&#xff0c;这是一种安装快速、简化部署和管理过程、与操作系统提供的包管理工具紧密集成的部署方法。此外&#xff0c;当你需要更高的灵活性和自定义性&#xff0c;并且愿意承担一些额外的手动配置和管理工作&am…

JavaScript高级 函数进阶篇

函数进阶 1、函数的定义和调用 函数声明方式function关键字&#xff08;命名函数&#xff09;&#xff1b;函数表达式&#xff08;匿名函数&#xff09;&#xff1b;new Function()&#xff08;此处的Function()是一个构造函数&#xff09;&#xff1b;var fn new Function(参…

IntelliJ IDEA 2020将SpringMVC项目打成war包

一 、打开 Project Structure 进行配置 1. 打开方式 &#xff08;1&#xff09;CtrlAltShiftS &#xff08;2&#xff09;File->Project Structure &#xff08;3&#xff09;点击如下图标&#xff1a; 2. 进入 Project Structure&#xff0c;添加Artifacts Web Applica…

YB75XXH系列是采用CMOS工艺制造,低功耗的高压稳压器

YB75xxH 高耐压线性稳压器 ■产品简介&#xff1a; YB75XXH系列是采用CMOS工艺制造&#xff0c;低功耗的高压稳压器&#xff0c;最高输入电压可达25V,输出电压范围为1.5V一12.0V。它具有高精度的输出电压、极低的供电电流、极低的跌落电压等特点。 ■产品特点&#xff1a; …

Python并行计算和分布式任务全面指南

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是彭涛&#xff0c;今天为大家分享 Python并行计算和分布式任务全面指南。全文2900字&#xff0c;阅读大约8分钟 并发编程是现代软件开发中不可或缺的一部分&#xff0c;它允许程序同时执行多个任务&#xff0…

spring基于Xml管理bean---Ioc依赖注入:对象类型属性赋值(1)----外部bean的引入(bean和bean之间的引入)

文章目录 注入普通属性的方式1、set方法注入2、构造器&#xff08;构造方法&#xff09;注入 总结&#xff1a;注入对象类型属性 注入普通属性的方式 1、set方法注入 2、构造器&#xff08;构造方法&#xff09;注入 总结&#xff1a; set方法注入和构造器方法的注入&#…

基于Netty构建Websocket服务端

除了构建TCP和UDP服务器和客户端&#xff0c;Netty还可以用于构建WebSocket服务器。WebSocket是一种基于TCP协议的双向通信协议&#xff0c;可以在Web浏览器和Web服务器之间建立实时通信通道。下面是一个简单的示例&#xff0c;演示如何使用Netty构建一个WebSocket服务器。 项目…