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

news2025/2/2 22:49:14

前言

双连通分量是无向图中的一个概念,它是指无向图中的一个极大子图,根据限制条件可以分为边双连通分量和点双连通分量,欲了解双连通分量需先了解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)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

简单了解一下当前火热的大数据 -- Kylin

神兽麒麟 一、Apache Kylin 是什么&#xff1f;二、Kylin架构结语 一、Apache Kylin 是什么&#xff1f; 由eBay公司中国团队研发&#xff0c;是一个免费开源的OLAP多维数据分析引擎优点 超快的响应速度&#xff0c;亚秒级支持超大数据集&#xff08;PB以上&#xff0c;千亿记…

数字人解决方案——ER-NeRF实时对话数字人模型推理部署带UI交互界面

简介 这个是一个使用ER-NeRF来实现实时对话数字人、口播数字人的整体架构&#xff0c;其中包括了大语言回答模型、语音合成、成生视频流、背景替换等功能&#xff0c;项目对显存的要求很高&#xff0c;想要达到实时推理的效果&#xff0c;建议显存在24G以上。 实时对话数字人 …

关于Python里xlwings库对Excel表格的操作(十六)

这篇小笔记主要记录如何【设置单元格数据的对齐方式】。 前面的小笔记已整理成目录&#xff0c;可点链接去目录寻找所需更方便。 【目录部分内容如下】【点击此处可进入目录】&#xff08;1&#xff09;如何安装导入xlwings库&#xff1b; &#xff08;2&#xff09;如何在Wps下…

MyBatis——MyBatis的延迟加载

MyBatis的延迟加载&#xff08;一对多查询案例&#xff09; 1.什么是延迟加载&#xff1f; 开启延迟加载后&#xff0c;在真正使用数据的时候才发起级联查询&#xff0c;不用的时候不查询。 2.pojo User类&#xff1a; package com.wt.pojo;import java.io.Serializable; …

Rust中peekable的使用

在 Rust 中&#xff0c;从迭代器中获取&#xff08;也就是“消费”&#xff09;一个元素时&#xff0c;每次调用 next 方法都会“消费”迭代器的一个元素&#xff0c;这意味着此元素被从迭代器中移除并返回给调用者&#xff0c; 一旦一个元素被消费&#xff0c;它就不能再次从同…

Python中的//, /, % 运算符详解与区别

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python中&#xff0c;//, /, % 是常用的数学运算符&#xff0c;用于执行整除、除法和取余操作。本文将深入探讨这三个运算符的作用、用法以及区别&#xff0c;并通过丰富的示例代码帮助大家更好地理解它们的用…

大数据开发职业介绍

........................................................................................................................................................... 大数据开发转正 ...................................................................................…

只更新软件,座椅为何能获得加热功能?——一文读懂OTA

2020年&#xff0c;特斯拉发布过一次OTA更新&#xff0c;车主可以通过这次系统更新获得座椅加热功能。当时&#xff0c;这则新闻震惊了车圈和所有车主&#xff0c;彼时的大家还没有把汽车当作可以“升级”的智能设备。 如今3年过去了&#xff0c;车主对各家车企的OTA升级早已见…

【三维生成与重建】ZeroRF:Zero Pretraining的快速稀疏视图360°重建

系列文章目录 题目&#xff1a;ZeroRF: Fast Sparse View 360◦ Reconstruction with Zero Pretraining 任务&#xff1a;稀疏重建&#xff1b;拓展&#xff1a;Image to 3D、文本到3D 作者&#xff1a;Ruoxi Shi* Xinyue Wei* Cheng Wang Hao Su &#xff0c;来自UC San Dieg…

PyTorch随机数生成:torch.rand,torch.randn,torch.randind,torch.rand_like

在用PyTorch做深度学习开发过程中&#xff0c;时常用到随机数生成功能&#xff0c;但经常记不住几个随机数生成函数的用法&#xff0c;现在正好有点时间&#xff0c;整理一下。 1. torch.rand() torch.rand(*size, *, generatorNone, outNone, dtypeNone, layouttorch.stride…

VBA_MF系列技术资料1-247

MF系列VBA技术资料 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧&#xff0c;我参考大量的资料&#xff0c;并结合自己的经验总结了这份MF系列VBA技术综合资料&#xff0c;而且开放源码&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-04属于定…

C语言操作符详解+运算符优先级表格

目录 前言 一、操作符是什么&#xff1f; 二、操作符的分类 三、算术操作符 四、逻辑操作符 五、比较操作符 六、位操作符 七、赋值操作符 八、其他操作符 九、运算符优先级表格 总结 前言 在编写程序时&#xff0c;最常用到的就是操作符&#xff0c;本文将详细的介绍…

C++ Qt开发:Charts绘图组件概述

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍QCharts二维绘图组件的常用方法及灵活运用。 …

Unity自带的NavMesh寻路组件

最近看了一下Unity自带的NavMesh寻路组件&#xff0c;先说一下基本的使用&#xff1a; 首先先把AI Navgation的package包给安装上。 给场景地图添加上NavMeshSurface组件&#xff0c;然后进行烘焙&#xff0c;烘焙出对应的场景地图文件。 给移动物体添加对应的Nav MeshAgent组…

C语言中的关键字

Static 静态局部变量 结果&#xff1a; a作为静态局部变量&#xff0c;第一次进入该函数的时候&#xff0c;进行第一次变量的初始化&#xff0c;在程序整个运行期间都不释放。&#xff08;因为下一次调用还继续使用上次调用结束的数值&#xff09; 但是其作用域为局部作用域&…

Android Studio 显示前进后退按钮

在写代码的过程中我们经常需要快速定位到先前或者往后的代码位置&#xff0c;可以使用Alt左右箭头 但是新安装的Android Studio工具栏上是没有显示左右箭头的工具按钮的&#xff0c;需要我们设置将Toolbar显示出来 View-Appearance-Toolbar 勾选即可 显示后

综述 2022-Briefings in Bioinformatics:多模态AI+生物医学数据(主要集中于多组学数据)

Stahlschmidt, Sren Richard, Benjamin Ulfenborg, and Jane Synnergren. "Multimodal deep learning for biomedical data fusion: a review." Briefings in Bioinformatics 23.2 (2022): bbab569. https://doi.org/10.1093/bib/ bbab569 被引次数&#xff1a;124 …

【数据库模拟题目集】选择题

数据库应用程序的编写是基于数据库三级模式中的&#xff08;外模式&#xff09; 对创建数据库模式一类的数据库对象的授权可由CREATE USER时实现。新创建的数据库用户有三种权限&#xff0c;CONNECT、RESOURCE和DBA。拥有RESOURCE权限的用户&#xff08;不能创建模式 &#xf…

怎么提取视频中的背景音乐?

当我们在刷视频的时候&#xff0c;有时候听到一个背景音乐很好听&#xff0c;但是又不知道歌名&#xff0c;比如英语歌&#xff0c;这个时候我们很难找到这首歌&#xff0c;相信有很多朋友会遇到这样的问题&#xff0c;不知道怎么弄&#xff0c;下面小编给大家推荐一些方法帮助…

TCP/IP:从数据包到网络的演变

引言 TCP/IP协议的起源可以追溯到20世纪60年代末和70年代初&#xff0c;美国国防部高级研究计划局&#xff08;ARPA&#xff09;研究开发一种可靠的通信协议&#xff0c;用于连接分散在不同地点的计算机和资源。 在当时&#xff0c;计算机之间的连接并不像现在这样普遍和便捷…