Tarjan算法学习笔记

目录

无向图的割点与桥

时间戳:

搜索树:

追溯值:

割边判定法则:

割点判定法则:

无向图的双连通分量

定理:

边双连通分量(e-DCC)的求法:

e-DCC的缩点:

有向图的连通性

追溯值:

Tarjan算法求强连通分量(SCC):


无向图的割点与桥

无向连通图G=(V,E):

若对于 x 属于 V,从图中删去节点 x 以及所有与 x 关联的边之后,G 分裂成两个或两个以上不相连的子图,则称 x 为 G 的割点

若对于 e 属于 E ,从图中删去边 e 之后,G 分裂成两个不相连的子图,则称 e 为 G 的割边

一般无向图(不一定连通)的“割点”和“桥”就是它的各个连通块恶的“割点”和“桥”。

Tarjan算法能够求出有向图的强连通分量、必经点与必经边。Tarjan算法是基于无向图的深度优先遍历。

时间戳:

在图的深度优先遍历过程中,按照每个节点第一次被访问的时间顺序,依次给与 N 个节点 1~N 的整数标记,给标记称为“时间戳”,记为 dfn[n]。

搜索树:

在无向连通图中任选一个节点出发进行深度优先遍历,每个点只访问一次。所有发生递归的边(x,y)(换言之,从x到y是对y的第一次访问)构成一棵树,我们把它称为“无向连通图的搜索树”。当然,一般无向图(不一定连通)的各个连通块的搜索树构成无向图的“搜索森林”。

追溯值:

 设 subtree[x] 表示搜索树中以 x 为根的子树。low[x] 定义为以下节点的时间戳的最小值。

1)subtree[x] 中的节点。

2)通过1条不在搜索树上的边,能够到达 subtree[x] 的节点。

根据定义,为了计算 low[x],应该先令 low[x]=dfn[x],然后考虑从 x 出发的每条边。

若在搜索树上 x 是 y 的父节点,则令 low[x]=min(low[x],low[y]).

若无向边(x,y)不是搜索树上的边,则令 low[x]=min(low[x],dfn[y]).

割边判定法则:

无向边(x,y)是桥,当且仅当搜索树上存在 x 的一个子节点 y ,满足:dfn[x]<low[y].

根据定义,dfn[x]<low[y] 说明从 subtree[y] 出发,在不经过 (x,y)的前提下,不管走那条边,都无法到达 x 或比 x 更早访问的节点。若把(x,y)删除,则 subtree[y] 就好像形成了一个封闭的环境,与节点 x 没有边相连,图断开成了两部分,因此(x,y)是割边。

反之,若不存在这样的子节点 y ,使得 dfn[x]<low[y],则说明每个 subtree[y] 都能绕行其他边到达 x 或比 x 更早访问的节点,(x,y)自然就不是割边。

桥一定是搜索树中的边,并且一个简单环中的边一定都不是桥。

特别需要注意, 因为我们遍历的是无向图,所以从每个点 x 出发,总能访问到它的父节点 fa。 根据 low 的计算方法,(x,fa) 属于搜索树上的边,且 fa 不是 x 的子节点,故不能用 fa 的时间戳来更新low[x] 。
但是,如果仅记录每个节点的父节点,会无法处理重边的情况——当 x 与 fa 之间有多条边时,(x,fa) 一定不是桥。 在这些重复的边中, 只有一条算是“搜索树上的边” 其他的几条都不算。 故有重边时, dfn[fa] 能用来更新 low[x]。
一个好的解决方案是:改为记录“递归进入每个节点的边的编号” 。编号可认为是边在邻接表中存储的下标位置。 这里介绍“成对变换”技巧。把无向图的每一条边看作双向边, 成对存储在下标 “2和3” “4和5” “6和7”处。若沿着编号为的边递归进入了节点 x ,则忽略从 x 出发的编号为 i xor 1 的边,通过其他边计算 low[x] 即可。

割点判定法则:

若 x 不是搜索树的根节点(深度优先遍历的起点),则 x 是割点当且仅当搜索树上存在 x 的一个子节点 y,满足:dfn[x] <= low[y]
特别地,若 x 是搜索树的根节点,则 x 是割点当且仅当搜索树上存在至少两个子节点 y1,y2 满足上述条件。
证明方法与割边的情形类似,这里就不再赞述。
因为割点判定法则是小于等于号,所以在求割点时, 不必考虑父节点和重边的问题,从X出发能访问到的所有点的时间戳都可以用来更新 low[x] 。

无向图的双连通分量

若一张无向连通图不存在割点,则称它为“点双连通图”。若一张无向连通图不存在桥,则称它为“边双连通图”。
无向图的极大点双连通子图被称为“点双连通分量”,简记为“v-DCC”。无向连通图的极大边双连通子图被称为“边双连通分量”,简记为“e-DCC”。 二者统称为“双连通分量”,简记为“DCC”。
在上面的定义中,我们称一个双连通子图 G'=(V',E')“极大” (其中 V' 属于 V , E' 属于 E ),是指不存在包含 G' 的更大的子图 G"=(V",E"),满足 V' 属于V"属于 V,E' 属于 P" 属于 E 并且 G" 也是双连通子图。

定理:

一张无向连通图是“点双连通图” ,当且仅当满足下列两个条件之一。
1).图的顶点数不超过2。
2).图中任意两点都同时包含在至少一个简单环中。其中“简单环”指的是不自交的环,也就是我们通常画出的环。

一张无向连通图是“边双连通图” ,当且仅当任意一条边都包含在至少一个简单环中。
证明:
该定理给出了无向连通图是“点双连通图”或“边双连通图”的充要条件。我们以“点双连通图”为例进行证明,“边双连通图”的证明类似。
对于顶点数不超过2的情况, 定理显然成立, 下面假设图中顶点数不小于3。先证充分性。若任意两点 x, y 都同时包含在至少一个简单环中,则 x,y 之间至少有两条不相交的路径。无论从图中删除哪个节点,x,y 均能通过两条路径之一相连。故图中不存在割点,是点双连通图。
再证必要性。反证法,假设一张无向连通图是“点双连通图” 并且存在两点 x,y,它们不同时处于任何一个简单环中。

如果 x,y 之间仅存在1条简单路径,那么路径上至少有一个割点,与“点双连通”矛盾。

如果 x,y 之间存在2条或2条以上的简单路径,那么容易发现,任意两条都至少有一个除x,y之外的交点:进一步可推导出, x,y之间的所有路径必定同时交于除 x,y 之外的某一点 p (不然就会存在两条没有交点的路径,形成一个简单环)
根据定义,p是一个割点,与“点双连通”矛盾。故假设不成立。证毕。

边双连通分量(e-DCC)的求法:

边双连通分量的计算非常容易。只需求出无向图中所有的桥,把桥都删除后,无向图会分成若干个连通块,每一个连通块就是一个“边双连通分量”。

在具体的程序实现中, 一般先用Tarjan算法标记出所有的桥边。然后,再对整个无向图执行一次深度优先遍历(遍历的过程中不访问桥边),划分出每个连通块。下面的代码在Taran求桥的参考程序基础上,计算出数组c,c[X]表示节点 x 所属的“边双连通分量”的编号。

e-DCC的缩点:

缩点:将一个强连通分量缩成一个点。

把每个 e-DCC 看作一个节点,把桥边 (x,y) 看作连接编号为 c[x] 和 c[y] 的 e-DCC 对应节点的无向边,会产生一棵树(若原来的无向图不连,则产生森林)。这种把 e-DCC 收缩为一个节点的方法就称为“缩点”。下面的代码在Tarjan求桥、求e-DCC的参考程序基础上,把e-DCC缩点,构成一棵新的树(或森林),存储在另一个邻接表中。

有向图的连通性

给定有向图 G=(V,E),若存在 r 属于 V,满足从 r 出发能够到达 V 中所有的点,则称G是一个“流图”(Flow Graph),记为 (G,r),其中 r 称为流图的源点。
与无向图的深度优先通历类似,我们也可以定义“流图”的搜索树和时间戳的概念。
在一个流图(G.r)上从 r 出发进行深度优先遍历,每个点只访问一次。所有发生通归的边 (x,y)(换言之,从 x 到是对 y 的第一次访问)构成一棵以 r 为根的树,我们把它称为流图(G,r)的搜索树。
同时,在深度优先遍历的过程中,按照每个节点第一次被访问的时间顺序,依次给子流图中N个节点1~N的整数标记,该标记被称为时间戳,记为dfn[x]。
流图中的每条有向边(x,y)必然是以下四种之一。

1).树枝边,指搜索树中的边,即x是y的父节点(一种特殊的前向边)
2).前向边,指搜索树中x是y的祖先节点
3).后向边,指搜索树中y是x的祖先节点。
4).横叉边,指除了以上三种情况之外的边,它一定满足 dfn[y]<dfn[x] .

给定一张有向图。岩对于图中任意两个节点,y,既存在从x到的路,也存在从y到x的路径,则称该有向图是“强连通图”

有向图的极大强连通子图被称为“强连通分量” 简记为SCC。 此处“极大”的含义与双连通分量“极大”的含义类似。

Tarjan 算法基于有向图的深度优先遍历,能够在线性时间内求出一张有向图的各个强连通分量。
一个“环” 一定是强连通图。如果既存在从x到y的路径,也存在从y到的那么x,y显然在一个环中。因此,Tarjan算法的基本思路就是对于每个点,尽找到与它一起能构成环的所有节点。

容易发现,前向边”(x,y)没有什么用处,因为搜索树上本来就存在从x到y。“后向边” (x,y) 非常有用,因为它可以和搜索树上从y到x的路径一起构成环。“横叉边” (x,y) 视情况而定,如果从y出发能找到一条路径回到x的祖先节点,那么(x,y)就是有用的。

为了找到通过“后向边”和“横叉边”构成的环,Tarjan 算法在深度优先遍历的同时维护了一个栈。当访问到节点x时,栈中需要保存以下两类节点。

1).搜索树上x的祖先节点,记为集合 anc(x)。
设y属于anc(x)。 若存在后向边(x,y),则(x,y) 与y到x的路径一起形成环。

2).已经访问过, 并且存在一条路径到达 anc(x) 的节点。
设z是一个这样的点,从出发存在一条路径到达y属于anc(x)。 若存在横叉边(x,2), 则(x,z)、z到y的路径、y到x的路径形成一个环。

综上所述,栈中的节点就是能与从x出发的“后向边”和“横叉边”形成环的节点。进而可以引入“追溯值”的概念。

追溯值:

设 subtree(x) 表示流图的搜索树中以x为根的子树。x的追溯值low[x]定义为满足以下条件的节点的最小时间戳。
1).该点在栈中。
2).存在一条从 subtree(x) 出发的有向边, 以该点为终点。

根据定义, Tarjan 算法按照以下步骤计算“追溯值”

1.当节点x第一次被访问时,把x入栈, 初始化low[x]=dfn[x]。

2.扫描从 x出发的每条边(x,y)。

        (1)若y没被访问过,则说明(x,y)是树枝边,递归访问y,从回潮之后,
        令low[x]=min(low[xl,lowly)。
        (2)若y 被访问过并且y在栈中,则令lowlx]= min(lowlxl.dfnly).
3.从x回溯之前,判断是否有lowlx]=dfn[x]。若成立,则不断从栈中弹出节点,直至x出栈。

__________________________________________________________________________

1).树枝边,指搜索树中的边,即x是y的父节点(一种特殊的前向边)
2).前向边,指搜索树中x是y的祖先节点
3).后向边,指搜索树中y是x的祖先节点。
4).横叉边,指除了以上三种情况之外的边,它一定满足 dfn[y]<dfn[x] .

如何判断某一点是否在某个强连通分量内:

情况一:存在后向边指向祖先节点。

情况二:先走到横叉边,横叉边再走到祖先节点。

Tarjan算法求强连通分量(SCC):

对每个点定义两个时间戳

dfn[u]表示遍历到u的时间戳

low[u]从u开始走,所能遍历到的最小时间戳是什么

u是其所在的强连通分量的最高点,等价于dfn[u]==low[u]

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

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

相关文章

智能分析网关V4+EasyCVR视频融合平台——高速公路交通情况的实时监控和分析一体化方案

随着2024年春运帷幕的拉开&#xff0c;不少人的返乡之旅也即将开启&#xff0c;从这几日的新闻来看&#xff0c;高速上一路飘红。伴随恶劣天气&#xff0c;加上激增的车流&#xff0c;极易导致高速瘫痪&#xff0c;无法正常使用。为解决此问题&#xff0c;助力高速高效运营&…

一些你可能用到的函数和头文件

对于排序想必大家应该挺熟悉的&#xff0c;如果要是给一连串打乱的整数让你由小到大排序&#xff0c;常见的方法有冒泡排序法和选择排序法等&#xff0c;今天我就给大家介绍一个十分好用的方法&#xff0c;就是使用 sort 函数来进行快排。 sort 函数是位于头文件 #include <…

R语言分析任务:

有需要实验报告的可CSDN 主页个人私信 《大数据统计分析软件&#xff08;R语言&#xff09;》 实 验 报 告 指导教师&#xff1a; 专 业&#xff1a; 班 级&#xff1a; 姓 名&#xff1a; 学 …

Linux fdisk命令教程:磁盘分区工具轻松创建和操作磁盘分区表(附实例详解和注意事项)

Linux fdisk命令介绍 fdisk&#xff08;format disk&#xff09;是一个在Linux中用于创建和操作磁盘分区表的菜单驱动的命令行实用程序。它允许您创建最多四个主分区&#xff0c;逻辑分区的数量取决于您使用的硬盘的大小。 Linux fdisk命令适用的Linux版本 fdisk命令在所有L…

Three.js 纹理贴图 - 环境贴图 - 纹理贴图 - 透明贴图 - 高光贴图

文章目录 Three.js 纹理贴图纹理贴图 map属性纹理贴图的映射方式 texture.Mapping纹理贴图的色彩空间 texture.colorSpace中途更新纹理的色彩空间 texture.needsUpdate 纹理加载器 THREE.TextureLoader监听单个材质监听多个材质 - LoadingManager类 1. 颜色贴图与材质的颜色2.渲…

Linux——存储管理

文章目录 基本分区磁盘简介磁盘分类linux的磁盘命名磁盘的分区方式 管理磁盘虚拟机添加硬盘查看磁盘信息磁盘分区流程创建分区创建文件系统挂载mount查看挂载信息 剩余空间继续分区MBR如何划分更多的分区为什么只能有4个主分区扩展分区的引入 逻辑卷LVM是什么特点术语创建LVMVG…

【STL-常用算法】

常用算法 概述: 算法主要是由头文件 algorithm functional numeric 组成algorithm是所有STL头文件中最大的一个&#xff0c;范围涉及到比较、 交换、查找、遍历操作、复制、修改等等numeric体积很小&#xff0c;只包括几个在序列上面进行简单数学运算的模板函数functional 定…

数据图表方案,企业视频生产数据可视化

在信息爆炸的时代&#xff0c;如何将复杂的数据转化为直观、生动的视觉信息&#xff0c;是企业在数字化转型中面临的挑战。美摄科技凭借其独特的数据图表方案&#xff0c;为企业在数据可视化领域打开了一扇全新的大门。 一、数据图表方案的优势 1、高效便捷&#xff1a;利用数…

vscode实时预览markdown效果

安装插件 Markdown Preview Enhanced 上面是搜索框 启动预览 右键->Open Preview On the Side 效果如下&#xff1a; 目录功能 目录功能还是使用gitee吧 push后使用gitee&#xff0c;gitee上markdown支持侧边生成目录

Android矩阵Matrix裁切setRectToRect拉伸Bitmap替代Bitmap.createScaledBitmap缩放,Kotlin

Android矩阵Matrix裁切setRectToRect拉伸Bitmap替代Bitmap.createScaledBitmap缩放&#xff0c;Kotlin class MyImageView : AppCompatImageView {private var mSrcBmp: Bitmap? nullprivate var testIV: ImageView? nullconstructor(ctx: Context, attrs: AttributeSet) :…

一步到位:用Python实现PC屏幕截图并自动发送邮件,实现屏幕监控

在当前的数字化世界中&#xff0c;自动化已经成为我们日常生活和工作中的关键部分。它不仅提高了效率&#xff0c;还节省了大量的时间和精力。在这篇文章中&#xff0c;我们将探讨如何使用Python来实现一个特定的自动化任务 - PC屏幕截图自动发送到指定的邮箱。 这个任务可能看…

解决Linux Shell脚本错误:“/bin/bash^M: bad interpreter: No such file or directory”

在Linux系统中运行Shell脚本时&#xff0c;你可能会遇到一个常见的错误&#xff0c;错误信息如下&#xff1a; -bash: ./xxx.sh: /bin/bash^M: bad interpreter: No such file or directory这个错误通常是由于Shell脚本文件中存在不兼容的换行符引起的。在Windows系统中&#…

YoloV8改进策略:Block改进|DCNv4最新实践|高效涨点|完整论文翻译

摘要 涨点效果:在我自己的数据集上,mAP50 由0.986涨到了0.991,mAP50-95由0.737涨到0.753,涨点明显! DCNv4是可变形卷积的第四版,速度和v3相比有了大幅度的提升,但是环境搭建有一定的难度,对新手不太友好。如果在使用过程遇到编译的问题,请严格按照我写的环境配置。…

Linux 系统开始配置

文章目录 备份源为root 设置密码安装基本工具切换root 用户删除snap从 Ubuntu 移除 Snap 后使用 deb 文件安装软件商店和 Firefox在 Ubuntu 系统恢复到 Snap 软件包总结 删除 vim安装neovim在线安装neovim压缩安装neovim安装lazyvim安装剪切板 安装qt配置 Qt 环境不在sudoers文…

链表中的数字相加

不能简单认为将两条链表转变为整数后进行运算&#xff0c;然后将结果转变为链表。因为如果链表很长&#xff0c;这可能会导致整数溢出。 在正常的两个整数加法运算时&#xff0c;我们是从低位开始&#xff0c;然后依次相加更高位的数字&#xff0c;所以不难想到我们需要将链表反…

Git提交忽略指定文件

1.创建.gitignore文件存放到和.git同级的根目录下 #提交git时要忽略的文件或者文件夹&#xff0c;根据自己的需求来写 .idea target*.log *.iml *.jar *.war *.nar *.ear *.zip *.rar *.tar.gz2.提交.gitignore文件文件到远程仓库 分两种情况 .idea、target等无关文件已经提交到…

(每日持续更新)jdk api之NotSerializableException基础、应用、实战

博主18年的互联网软件开发经验&#xff0c;从一名程序员小白逐步成为了一名架构师&#xff0c;我想通过平台将经验分享给大家&#xff0c;因此博主每天会在各个大牛网站点赞量超高的博客等寻找该技术栈的资料结合自己的经验&#xff0c;晚上进行用心精简、整理、总结、定稿&…

【动态规划】【记忆化搜索】【回文】1312让字符串成为回文串的最少插入次数

作者推荐 【动态规划】【字符串】【表达式】2019. 解出数学表达式的学生分数 本文涉及知识点 动态规划汇总 记忆化搜索 回文 字符串 LeetCode1312. 让字符串成为回文串的最少插入次数 给你一个字符串 s &#xff0c;每一次操作你都可以在字符串的任意位置插入任意字符。 请…

基于Java SSM框架实现校园快领服务系统项目【项目源码+论文说明】

基于java的SSM框架实现校园快领服务系统演示 摘要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于校园快领服务系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了…

Python爬虫的基本原理

我们可以把互联网比作一张大网&#xff0c;而爬虫&#xff08;即网络爬虫&#xff09;便是在网上爬行的蜘蛛。把网的节点比作一个个网页&#xff0c;爬虫爬到这就相当于访问了该页面&#xff0c;获取了其信息。可以把节点间的连线比作网页与网页之间的链接关系&#xff0c;这样…