连通性1(Tarjan 理论版)

news2025/1/10 17:16:50

目录

一、无向图割点、桥、双连通分量

 Tarjan 算法求割点和桥(割边)

“割点”代码

边双和点双连通分量

边双连通分量 和 点双连通分量 的缩点

二、有向图强连通分量

1.有向图的弱连通与强连通

2.强连通分量

Kosaraju算法

Tarjan 算法(求强连通分量)


一、无向图割点、桥、双连通分量

  • 给定无向连通图 G = (V, E)
  • 对于一个点 x,若从图中删除 x 及所有与 x 相连的边,图不再连通,x 是 G 的割点
  • 对于一条边 e,从图中删去 e,图不再连通, e 是 G 的割边
  • 一个图如果不存在割点,则它是一个点双连通图,一个图的极大点双连通子图是它的点双连通分量
  • 一个图如果不存在割边,则它是一个边双连通图,一个图的极大边双连通子图是它的边双连通分量

先借用OI Wiki (传送门)的图解释几种边:

 Tarjan 算法求割点和桥(割边)

  • 时间戳 dfn:第几个搜到这个点
  • 返祖边:搜索树上一个点连向它另一条支链上的点的边
  • (横插边:在搜索树上一个点连向它另一条支链上的点的边——在无向图不存在【因为下一条支链在dfs序中会直接接在当前这条支链后面成为“子树”】
  • 追溯值 low:当前点及其子树通过一条返祖边能连到的最小 dfn 值
  • 如果 <u, v> 是搜索树的边low[u] = min(low[u], low[v])
  • 如果 <u, v> 是返祖边:low[u] = min(low[u], dfn(v))

下面来看一个连通图,寻找割点和割边(桥)所满足的规律。右图为左图的一个dfs搜索树,水蓝色标记每个点的dfn(时间戳),梅红色标记每个点的 low 值。

low 值从叶节点开始标记,因为其值作为子节点可以向上更新父节点的 low 值,比如序号为4的点有一条连向1号节点的返祖边,其 low 值为1,7号结点 low 值等于其 dfn = 9,10号结点 low 值也为8,而对于8号结点,它的子树中4号结点 low 值为1,根据 “ 如果 <u, v> 是搜索树的边:low[u] = min(low[u], low[v]) ” ,其 low 值为1 ,再依次向上更新。

例如:10号点为割点,若将其去掉,其下的7号结点无法与上面的连通。

规律:【割点有两类】

  1. 子树里不存在跨越它连向它上方的点的边
  2. 有多个儿子的根

(u, v)割边(u 为父亲,v 为儿子):以 v 为根的子树中不存在连向 u 以及 u 上方的边。

用low和dfn的关系表示即

  • u点是割点, v 是 u 搜索树上的一个儿子:① dfn[u] <= low[v] —— v的子树中没有返祖边能跨越 u 点;② 有多个儿子的根节点
  • 边是桥,搜索树上 v 是 u 的一个儿子:dfn[u] < low[v] —— v 的子树中没有返祖边能跨越<u,v> 这条边

注意割点的式子有等号,判割边没有等号(如果有一条返祖边将 v 与 u 相连,则dfn[u] = low[v] ,这时原本v和u相连的边删掉也能连通,故u-v不是割边) 

“割点”代码

注意第32行为 dfn[y],与第25行的 low[y] 不一样。在求“割边”里写成 low[y] 虽然也不会错,但在求割点里就是错的,可能有些题目数据不够强这里写错了也能过,但一旦错了就很难找到,所以极度建议割点割边代码此处按照定义写成一致,能大大减少出错率。

关于为什么写low[y]为错的说明:

如下图,因为搜索的顺序不确定(取决于建图时的顺序)若3号点的low值通过一条返祖边更新为1后,再来更新5号结点时,若是 low[x] = min(low[x],low[y]),low[5]=low[3]=1,然后4号点就会继承5号点的 low 值也为1,这样dfn[3]>=low[4],就会误判点3不是割点,而事实上3号点是割点。这里相当于是将1--3这条返祖边与3--5这条返祖边连起来当成了1--5的返祖边,而我们的low值定义是当前点及其子树通过一条返祖边能连到的 最小dfn 值。5到3,3再到1,而3恰是我们的割点,而求割边的时候就不会出现这种情况,跨越了一条边就是跨越了一条边,不会存在要两条边连在一起才跨越一条边。

 

边双和点双连通分量

  • 把桥删了每个连通块都是一个边双连通分量——标记处桥之后dfs一遍即可
  • 点双连通分量要复杂一些——一个割点可能属于多个双连通分量

 

 dfs时(这里假设在8号结点先搜向9的那条支链)……9入栈,6入栈,10入栈,再向上返回(系统dfs递归调用的返回,系统栈的10,6,9弹出,自己维护的栈没有弹出)当返回到结点8时,dfn[8] <= low[y],判断8为割点,此时弹出自己维护的栈里8以上的所有结点(10,6,9)与8组成一个点双连通分量;8再到7号结点,发现7号结点没有儿子结点了,再返回,又成立dfn[8]<=low[7],8为割点,于是弹出7号点与8组成第二个点双连通分量;8再到4,发现low[4]=1,low[4] < dfn[8],8不是其中的割点……到最后回到根节点1,因为所有的结点的low值总不会比根节点的dfn还要小,即只有一个子节点的根节点总是割点,所以靠1号根节点将剩余的所有点弹出,组成最后一个点双连通分量。(无所谓,根节点会出手

边双连通分量 和 点双连通分量 的缩点

  • 每个边双连通分量缩成一个点,再用原来的桥把它们连起来
  • 点双连通分量因为一个割点可能包含在多个点双连通分量里面,所以我们将每个割点保留割点与其所在的点双连通分量连边即可。

如上图的点双连通分量可改为:

 

二、有向图强连通分量

1.有向图的弱连通与强连通

2.强连通分量

 如上图的黄色点构成一个强连通分量。

Kosaraju算法

 

对左图,从1开始搜:1进栈,5进栈,8进栈,4进栈,3进栈,3不能往下搜了,3出栈,回到4,4也没有向下搜的点,4出栈,回到8,6进栈,6出栈,8出栈,5出栈,1出栈;

然后再找图中一个没有访问过的点继续上述操作,从2开始,2入栈,2出栈;

再从7开始,7入栈,9入栈,9出栈,7出栈。

得到出栈顺序:3,4,6,8,5,1,2,9,7

再以这个出栈时间的逆序反图(即原来A->B变为B->A)进行dfs:从7开始,7无法到达其它点,7独自为一个强连通分量;再看9,因为9原本能去到的7已经被删了,9也单独是一个强连通分量;2号点为一个强连通分量;1号点为一个强连通分量(原本可以通向的2号点已经成为一个单独的强连通分量了);又5->3->4->8,3->6,所以5,3,4,6,8为一个强连通分量

原理:在一个 dfs 搜索树里面,越先出栈说明越多的点可以到达这个点,即在它后面的点都能到达它,如【3,4,6,8,5,1】3后面的点都能到达3,4后面的点都能到达4,依此类推。若顺序为A, B, C, 则实际图中关系为 A<--B<--C,那么倒叙,反图能到(C-->B)也即原图有反向边能到(C<--B)【意会~意会~】 

Tarjan 算法(求强连通分量)

 

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

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

相关文章

读书笔记:Python绘制三维图像 ← 斋藤康毅

下文给出了绘制函数 的 Python 代码。 很显然&#xff0c;这是一个三维图像。【绘制三维图像的Python代码】 import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3Dfigplt.figure() axAxes3D(fig) x1np.arange(-3.0, 3.0, 0.1) x2np.…

python刷题-关于日期、正则表达式的题

目录标题1、计算日期范围内的所有日期2、将Unix时间戳转换为格式化日期3、计算日期数据周同比4、正则表达式判断字符串是否是日期5、从文本中提取手机号码 --正则表达式6、批量提取网页上的手机号码7、自动提取电子邮箱地址8、验证用户密码是否规范-re.findall9、提取商品价格1…

ELK简介

什么是ELKE: Elasticsearch全文搜索引擎L: logstash日志采集工具K: kibana ES的可视化工具ELK是当今业界非常流行的日志采集保存和查询的系统我们编写的程序,会有很多日志信息,但是日志信息的保存和查询是一个问题IDEA控制台是一个临时显示的位置,我们可以将它保存在文件中但是…

Jetpack架构组件库:Room

Room Room是一款轻量级orm数据库&#xff0c;本质上是一个基于SQLite之上的抽象层。它通过注解的方式提供相关功能&#xff0c;编译时自动生成实现Impl&#xff0c;相比纯 SQLite 的API使用方式更加简单。另外一个相比于SQLite API的优势是&#xff1a;它会在编译时检查 SQL 语…

SpringBoot+Vue项目在线视频教育平台

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 浏…

网络原理之HTTP/HTTPS、TCP、IP四层协议栈

文章目录一、应用层&#xff08;一&#xff09;xml协议&#xff08;二&#xff09;json协议&#xff08;三&#xff09;protobuffer协议&#xff08;四&#xff09;HTTP协议1. 抓包工具&#xff0c;fiddler2. HTTP报文格式3. HTTP请求(Request)&#xff08;1&#xff09;URL基本…

【VisualBasicApplication】Excel编程

VBAExcel的宏与VBA宏的录制宏的启动运行快捷键运行宏&#xff1a;使用Excel对象运行宏*VBA的数据类型字符串&#xff08;String&#xff09;整形&#xff08;Integer&#xff09;和长整形&#xff08;Long&#xff09;单精度浮点型&#xff08;Single&#xff09;和双精度浮点型…

3.mysql查询必备sql语句

文章目录1.条件查询 where2. 通配符与模糊查询3. 映射4. 排序 order_by5. 取部分 limit 和offset6. 分组 group by7.左右连表 left outer join ... on8. 联合查询 union1.条件查询 where 表内容&#xff1a; import pymysqlconn pymysql.connect(host127.0.0.1,port3306,u…

向QAbstractItemView子类如:QTreeView、QTableView等子项单元格插入窗体小部件的功能实现(第2种方法)

1.前言工作中经常会遇到这样的需求&#xff1a;向QAbstractItemView子类如QTreeView、QTableView单元格插入窗体小部件&#xff0c;如&#xff1a;进度条、按钮、单行编辑框等。下面链接的系列博文就是讲解如何实现该功能的。《向QAbstractItemView子类如:QTreeView、QTableVie…

LeetCode 2500. 删除每行中的最大值

给你一个 m x n 大小的矩阵 grid &#xff0c;由若干正整数组成。 执行下述操作&#xff0c;直到 grid 变为空矩阵&#xff1a; 从每一行删除值最大的元素。如果存在多个这样的值&#xff0c;删除其中任何一个。 将删除元素中的最大值与答案相加。 注意 每执行一次操作&#…

行为型模式-状态模式

1.概述 【例】通过按钮来控制一个电梯的状态&#xff0c;一个电梯有开门状态&#xff0c;关门状态&#xff0c;停止状态&#xff0c;运行状态。每一种状态改变&#xff0c;都有可能要根据其他状态来更新处理。例如&#xff0c;如果电梯门现在处于运行时状态&#xff0c;就不能…

时序数据处理中的拟合问题

对于深度学习或机器学习模型而言,我们不仅要求它对训练数据集有很好的拟合(训练误差),同时也希望它可以对未知数据集(测试集)有很好的拟合结果(泛化能力),所产生的测试误差被称为泛化误差。度量泛化能力的好坏,最直观的表现就是模型的过拟合(overfitting)和欠拟合(…

一起Talk Android吧(第四百七十五回:渐变类视图动画)

文章目录使用方法属性介绍示例代码共用属性各位看官们大家好&#xff0c;上一回中咱们说的例子是"如何使用视图动画",这一回中咱们说的例子是"渐变类视图动画"。闲话休提&#xff0c;言归正转&#xff0c;让我们一起Talk Android吧&#xff01; 看官们&am…

移动web动画

移动web动画动画动画属性鼠标经过暂停动画多组动画鼠标经过暂停动画多组动画动画 动画最大的特点可以不用鼠标触发&#xff0c;自动的&#xff0c;反复的执行某些动画。 动画使用分为定义和调用&#xff1a; 定义&#xff1a; /* 1. 定义的动画 */ keyframes dance {from {tr…

恶意代码分析实战 12 对抗反汇编

12.1 Lab15-01 问题 这个二进制程序中使用了何种对抗反汇编技术&#xff1f; 首先&#xff0c;使用IDA载入该文件。 我们可以看到这个程序在地址0040100E处存在一个对抗反汇编技术的痕迹。 eax总是被置为零&#xff0c;jz跳转总是被执行。所以我们认为这一行是假冒的call指…

Docker的架构设计

前面我们研究了Docker容器的本质是一个特殊的进程&#xff0c;那么这个特殊进程是如何创建、如何终止的那&#xff1f;也就是说是谁来管理这个容器进程的生命周期的那&#xff1f;在mac操作系统中我们可以通过活动监视器来观察操作系统里面有哪些进程&#xff0c;以及通过活动监…

推荐算法:序列召回

目录 序列召回&#xff08;一&#xff09; 序列召回&#xff08;二&#xff09; 序列召回&#xff08;三&#xff09; 序列召回&#xff08;四&#xff09; 序列召回&#xff08;一&#xff09; 源自论文&#xff1a;http://arxiv.org/abs/1511.06939 基于GRU的序列召回中通过…

青训营项目实战1

项目实战 实现掘金青训营报名页码的后端部分 需求描述 展示话题&#xff08;标题、文字描述&#xff09;和回帖列表 不考虑前端页面实现&#xff0c;仅实现一个本地web服务 话题和回帖数据用文件存储 附加要求&#xff1a; 支持发布帖子 本地id生成要保证不重复 append文件 更…

【ONE·C || 指针】

总言 C语言&#xff1a;指针的使用介绍。 文章目录总言1、指针初阶1.1、是什么1.2、指针和指针类型1.2.1、指针类型介绍1.2.2、作用一&#xff1a;指针解引用1.2.3、作用二&#xff1a;指针整数1.3、野指针1.3.1、野指针是什么1.3.2、为什么存在野指针1.3.3、如何避免野指针1.4…

ReentrantLock从入门到踢门

1. ReentrantLock是什么Lock提供了比synchronized方法和语句更广泛的锁定操作。 更灵活的结构化&#xff0c;并且支持多个相关联的对象Condition。它实现了Lock、Serializable序列化接口。图1 ReentrantLock实现接口图1.1 Lock1.1.1 lock// 获取锁 void lock();1.1.2 lockInter…