点双连通分量&边双联通分量详解

2023-10-27

点双连通分量

前言

由于点双和边双都是无向图里面的东西,所以下面的讲解都以图是无向图作为前提。

概念

割点: 对于一个连通图中的点 x x x,假如删去这个点以及与所有 x x x 相连的边之后图不连通,那么称 x x x 为该图的割点

点双联通的: 对于一个无向图,假如仅仅对于该图而言其中不包含割点,那么称这个图是点双连通的。(和网上的不一样?别急,往下看)

点双连通分量: 对于一个无向图中的极大点双连通的子图,我们称这个子图为点双连通分量

为了方便,下面简称点双连通分量为点双。

性质

1、 除了一种比较特殊的点双,其他的点双都满足:任意两点间都存在至少两条点不重复路径。

比较特殊的点双:
在这里插入图片描述
网上大部分以该性质作为点双的定义,然后说这种图虽然不满足定义,但是是一个特殊的点双。而上面那个更严谨的定义则可以将这种情况包含在内,更加完备。

2、 图中任意一个割点都在至少两个点双中。

因为删去割点后图会不连通,所以割点至少连接着图的两部分,而由于点双中不能有割点,所以这两部分肯定不在同一个点双中,所以割点至少存在于两个点双中。

再次提醒,点双联通的的定义是 仅仅对于该图而言 其中不包含割点,那么称这个图是点双连通的,也就是说,可以包含原图中的割点。

3、 任意一个不是割点的点都只存在于一个点双中。

这个很显然,不多解释。

找割点

d f n [ x ] dfn[x] dfn[x] 表示遍历到 x x x 之前遍历过多少个点, l o w [ x ] low[x] low[x] 表示从 x x x 出发在不经过父子边的情况下能到达的最早的祖先的 d f n dfn dfn 值。

回看割点的定义:把这个点删除后图会不连通,那么肯定存在一些点,在不经过该割点的情况下无法到达割点的祖先,用这个性质来找就好了。

代码:

int dfn[maxn],low[maxn],id;
bool cut[maxn];
void dfs1(int x,int from)//from表示x与父亲之间的边的编号
{
	dfn[x]=low[x]=++id; int son=0;
	for(int i=first[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(y==(from^1))continue;//不能通过反向边走回去
		if(!dfn[y])
		{
			dfs1(y,x); son++;
			if(low[y]<low[x])low[x]=low[y];//更新low,假如y能走到更小的,那么x也能走到
			if(low[y]>=dfn[x])cut[x]=true;
			//假如儿子在不经过父子边的情况下不能到达x的祖先,那么x就是个点
		}
		else if(dfn[y]<low[x])low[x]=dfn[y];//假如走到了一个dfn更小的,那么更新low
	}
	if(fa==-1&&son==1)cut[x]=false;//特判出发点在一个环中的情况
}
void tarjan()
{
	for(int i=1;i<=n;i++)//如果图不连通,那么每一个连通块都要跑一遍
	if(dfn[i]==0)dfs1(i,-1);
}

再说说那个特判,是用来处理这种情况的:
在这里插入图片描述
假如从红色节点出发,那么最后红色节点会被判定成割点,因为没有儿子能走到它的祖先,但是他压根就没有祖先啊,所以这时候,我们判一下,假如没有祖先,那么不能算割点,于是有了

fa==-1

这个判定条件。

但是

son==1

这个条件用来干啥?

我们注意到,出发点也有是割点的情况,比如:
在这里插入图片描述
如果从红色节点出发,而此时红色节点又刚好是割点,那怎么办呢?

这时候就要用到

son==1

这个限制了,因为如果起点是割点,那么 s o n son son 肯定大于 1 1 1

发现只有遍历到一个 d f n [ y ] = 0 dfn[y]=0 dfn[y]=0 y y y 时, s o n son son 才会 + 1 +1 +1,所以 s o n son son 的实际意义就是该点所连接的点双数量。

而根据上面的性质,假如 s o n = = 1 son==1 son==1,那么这个点肯定不是割点,否则一定是割点,所以在 f a = − 1 fa=-1 fa=1 的同时我们还需要进行 s o n = 1 son=1 son=1 这样的判断。

那可能有人会问了,为什么其他的割点不用 s o n = 1 son=1 son=1 这样的方法来判呢?仔细想想,其他的点和出发点的区别就是:他们都有父亲。而遍历的时候是不能往回走的,也就是说,我们不知道父亲的状态,所以不能用 s o n son son 来判。

找点双

这个时候就要请出伟大的 Tarjan 了!

我们依然考虑使用上面的 d f n dfn dfn l o w low low 来求,我们将深搜时遇到的所有加入到栈里面,当找到一个割点的时候,就将这个割点往下走到的所有边弹出,而这些边所连接的点就是一个点双了。

代码:

int dfn[maxn],low[maxn],id,t;
edge zhan[(maxn*maxn)<<1];//存边的栈
int belong[maxn],cnt;//belong记录每个点属于哪一个点双,cnt记录点双个数
bool cut[maxn];
set<int> s[maxn];//记录每个点双包含哪些点,如果题目不需要也可以不求
void dfs(int x,int from)
{
	dfn[x]=low[x]=++id; int son=0;
	for(int i=first[x];i;i=e[i].next)
	{
		if(i==(from^1))continue;
		int y=e[i].y;
		if(!dfn[y])
		{
			zhan[++t]=e[i]; dfs(y,i); son++;//先压栈再遍历
			if(low[y]<low[x])low[x]=low[y];
			if(low[y]>=dfn[x])//发现x是割点
			{
				cnt++; edge xx; cut[x]=true;
				do{
					xx=zhan[t--];//弹出
					belong[xx.x]=belong[xx.y]=cnt;//标记
					s[cnt].insert(xx.x);s[cnt].insert(xx.y);//记录
				}while(xx.x!=x||xx.y!=y);//假如已经弹到 x到y 这条边了,就停下来
			}
		}
		else if(dfn[y]<low[x])low[x]=dfn[y];
	}
	if(from==-1&&son==1)cut[x]=false;
}

附赠题表

Knights of the Round Table   题解
[HNOI2012]矿场搭建   题解
[ZJOI2004]嗅探器   题解


边双连通分量

概念

割边: 假如删去这条边后图不连通,那么称这条边为割边。

边双联通的: 对于一个图,假如仅仅对于该图而言其中没有割边,那么我们称这个图是边双联通的

性质

1、 割边不属于任意边双,而其它非割边的边都属于且仅属于一个边双。

2、 对于一个边双中的任意两个点,它们之间都有至少两条边不重复的路径。

找割边

和找割点类似,直接上代码:

int dfn[maxn],low[maxn],id;
bool cut[maxn];
void dfs(int x,int from)
{
    dfn[x]=low[x]=++id;
    for(int i=first[x];i;i=e[i].next)
    {
        if(i==(from^1))continue;
        int y=e[i].y;
        if(!dfn[y])
        {
            dfs(y,i);
            if(low[y]<low[x])low[x]=low[y];
            if(low[y]>dfn[x])cut[i]=cut[i^1]=true;
            //注意这里是大于而不是大于等于,原因想想就明白了
        }
        else if(dfn[y]<low[x])low[x]=dfn[y];
    }
}

找边双

做法1

在请出Tarjan之前,我们先介绍另外一种做法:第一次 d f s dfs dfs 找出割边,然后第二次 d f s dfs dfs 在不经过割边的情况下遍历所有点,每一次遍历经过的一个子图就是一个边双。

做法2

用类似找点双的做法,但是栈里面压点,不压边。

代码:

int dfn[maxn],low[maxn],belong[maxn],id=0,cnt=0;
int zhan[maxn],t=0;
void dfs(int x,int from)
{
	dfn[x]=low[x]=++id;zhan[++t]=x;
	for(int i=first[x];i;i=e[i].next)
	{
		if(i==(from^1))continue;
		int y=e[i].y;
		if(!dfn[y])
		{
			dfs(y,i);
			if(low[y]<low[x])low[x]=low[y];
		}
		else if(dfn[y]<low[x])low[x]=dfn[y];
	}
	if(dfn[x]==low[x])
	{
		cnt++; int xx;
		do{
			xx=zhan[t--];
			belong[xx]=cnt;
		}while(xx!=x);
	}
}

题表

Caocao’s Bridges   题解
[CERC2015]Juice Junctions   题解
[USACO06JAN]冗余路径Redundant Paths   题解

一点个人感想

对于什么时候用点双,什么时候用边双这个问题,个人感觉是,点双的性质其实比边双要好,因为边双里面允许有割点的存在,边双只强调点集内所有点能相互到达,但点双就有一些更好的性质,比如像吃掉一个点之后剩下的点之间还能相互到达。

当然这些都是乱吹的,建议不看跳过即可。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

点双连通分量&边双联通分量详解 的相关文章

随机推荐

  • 【计算机网络篇】TCP协议

    作者简介 大家好 我是小杨 个人主页 小杨 的csdn博客 希望大家多多支持 一起进步呀 TCP协议 1 TCP 简介 TCP Transmission Control Protocol 是一种在计算机网络中广泛使用的传输层协议 用于在网络
  • [机器学习与scikit-learn-29]:算法-回归-普通线性回归LinearRegression拟合线性分布数据的代码示例

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 目录 第1章 LinearRegression类说明 第2章 LinearRegression使用的代码示例 2 1 导入库 2 2 导数数
  • SSM框架的流程及优点

    SSM框架 SSM Spring SpringMVC MyBatis 框架集由Spring MyBatis两个开源框架整合而成 SpringMVC是Spring中的部分内容 在这个快速发展的互联经济的时代 SSM框架提高了开发人员的工作效率
  • 查询topn的另一种方法通过orderby排序后利用limit来实现

    文章目录 前言 1 热身题实践 其他 前言 一直有个想法 把面试需要的知识点全都总结一下 包括数据库 语言 算法 数据结构等知识 形成一个面试总结笔记 这样以后面试的时候只看这些文章回顾下就行了 今天就先总结下Mysql的面试热身题吧 后续
  • HBase运维中遇到的问题

    1 PleaseHoldException Master is initializing hadoop 3 2 1 hbase 2 2 5 各种配置之后 出现的错误具体为 进去 hbase shell 之后 出现 hbase main 00
  • C#协变

    namespace 协变 public class Animal public string name public Animal string name1 name name1 public class dog Animal public
  • 【vue】vue 中插槽的三种类型:

    文章目录 一 匿名插槽 二 具名插槽 三 作用域插槽 一 匿名插槽
  • CSS学习笔记——搭建京东购物车网页

    大家好 作为一名互联网行业的小白 写博客只是为了巩固自己学习的知识 但由于水平有限 博客中难免会有一些错误出现 有不妥之处恳请各位大佬指点一二 博客主页 链接 https blog csdn net weixin 52720197 spm
  • elasticsearch心得记录-搭建到使用过程中

    1 es评分机制 使用场景 匹配多个关键词的时候 增加其中某个关键词的权重 增加其评分 搜索出来即可排到前面 评分默认为倒叙排 2 es基础的增删改查 搜索 search type dfs query then fetch 每个分片会根据
  • 条码规范——Code 93

    CODE 93 BACKGROUND INFORMATION Code 93 was designed to complement and improve upon Code 39 Code 93 is similar in that it
  • 在线代码测试小项目

    小项目 代码在线测试 http是我们生活中最常使用的协议 现如今网络浏览器越来越贴近人们的生活 使得做什么事都很方便 但是想要运行一段代码还得需要在电脑指定的环境下来运行 这在有些情况下让人很抓狂 我在网上也看到过很多代码在线测试的网页 感
  • 模块打包器Webpack详解!

    Webpack 1 什么是Webpack Webpack 是一个前端资源加载 打包工具 它将根据模块的依赖关系进行静态分析 然后将这些模块按照指定的规则生成对应的静态资源 从图中我们可以看出 Webpack 可以将多种静态资源 js css
  • 关于c语言main函数中int argc,char **argv的理解

    关于c语言main函数中int argc char argv的理解 c语言main函数通常形如int main int argc char argv 那么argc和argv代表啥呢 其实 argc表示传入main函数的参数的个数 而argv
  • Spark【Spark SQL(四)UDF函数和UDAF函数】

    UDF 函数 UDF 是我们用户可以自定义的函数 我们通过SparkSession对象来调用 udf 的 register name String func A1 A2 A3 方法来注册一个我们自定义的函数 其中 name 是我们自定义的函
  • MATLAB机器学习方法之朴素贝叶斯算法

    朴素贝叶斯分类算法的核心算法是 或 而如果所有特征都相互独立的话 P 特征 类别k 可以看作 P 特征1 类别k P 特征2 类别k P 特征3 类别k P 特征n 类别k 那么分别计算P 特征 类别1 P 特征 类别2 P 特征 类别3
  • paddlenlp二分类引入评估召回率F1指标 paddle.metric Accuracy

    每个具体的参数代表什么 明确好 无非就是第几个样本 属于某个类别的概率 非常清晰 from paddlenlp metrics import AccuracyAndF1 paddle no grad def evaluate model c
  • 基础知识——BCD码

    十六进制转二进制 将每一位十六进制转化为4位二进制位即可 BCD码 将十进制的每一位转化为4位二进制位即可 转换方法都是将每一位转为4位二进制位 但是区别是一个对应的是十六进制 一个对应的是十进制 比如给出二进制数0101 0101 如果对
  • muduo Timestamp详解

    1 简介 Timestamp用于提供时间戳相关的工具函数 2 类与接口 string toString const 返回时间的字符串形式 例如1649224501 687051 string toFormattedString bool s
  • 在word中插入分页符,多出一行

    类似问题在网上也有多次提及 例如 1 ctrl enter进行分页 但是下一页开头总是多出一行 2 Word换页时 上一页多了一行看不见的行 影响下页的标题编辑 3 word2007分页出现问题 分后多出一行 删除了后面的格式没了 4 wo
  • 点双连通分量&边双联通分量详解

    文章目录 点双连通分量 前言 概念 性质 找割点 找点双 附赠题表 边双连通分量 概念 性质 找割边 找边双 做法1 做法2 题表 一点个人感想 点双连通分量 前言 由于点双和边双都是无向图里面的东西 所以下面的讲解都以图是无向图作为前提