Tarjan算法初探 (1):Tarjan如何求有向图的强连通分量
在此大概讲一下初学Tarjan算法的领悟( QwQ)
Tarjan算法 是图论的非常经典的算法 可以用来寻找有向图中的强连通分量 与此同时也可以通过寻找图中的强连通分量来进行缩点
首先给出强连通分量的定义:
若在有向图G中 存在u到v的路径的同时也存在v到u的路径 则称u与v是强连通的 若G中所有点之间两两之间是强连通的则称G为一个强连通图 一个有向非强连通图的极大强连通子图称为强连通分量
极大强连通子图:G是一个极大强连通子图 当且仅当G是一个强连通图 同时不存在另一个强连通图G'使G是它的真子集
下面 的2 3 4 三个点构成一个强连通分量 同时1也是一个强连通分量

通过观察强连通分量的定义我们可以发现 如果通过dfs遍历含有强连通分量的图 一个点可能与它的子节点在同一个强连通分量中 或者与父节点在同一个强连通分量 若点V延伸出的dfs搜索树中有节点跟V有连边就意味着这个节点回溯回来的路径上的所有点与V强连通 同时点V延伸的搜索树中不一定只有一个节点满足这样的条件 而当把这样的节点找全以后 就求出了以V节点为根节点的搜索树中所有与V强连通的点
但是这样操作并没有考虑V的父节点或祖父节点即此时求得的并不一定是一个强连通分量只能说明这些点强连通 但最终一定能求出包含dfs起点的强连通分量(以dfs起点为根节点的搜索树中必定包含所有与起点强连通的点)
但若要求求出所有强连通分量 则不管算法的时间复杂度 求出整张图的强连通分量需要暴力枚举每一个点才能得到所有强连通分量 而这样时间复杂度会达到n2 级别
看起来不错但操作过于暴力所以让我们想一想有没有更好的做法?在遍历V的搜索树时 它的子节点不仅可能有边连接V 还可能连接到V的父节点或祖先节点或其他与V强连通的点 有没有什么方法能够利用这一点来简化算法?或者怎样唯一确定V是一个强连通分量的根节点?(确定一个点V 而所有与V强连通的点在以V为节点的搜索树中)

若以1点为dfs起点可以求出包含1的强连通分量 但不能在搜索完以2点为根节点的搜索树时判断2是否是一个强连通分量的根节点
接下来正式开始介绍Tarjan算法:
Tarjan算法基于dfs
强连通分量在dfs中的根节点延伸的搜索树中包含所有与根节点强连通的点(废话)
强连通分量是由环构成(废话*2)
那么一个点V是一个强连通分量的根节点的条件是在它的搜索树中没有节点能访问到它的父节点或祖先 否则V可与它的父亲或祖先节点构成一个环故与V强连通的点的集合属于与V的父亲或祖父节点强连通的点的集合 同时点V若与它的祖父节点或父节点相连 那么它的祖父或父亲节点所在强连通分量的根节点显然与点V所在的强连通分量的根节点相同
再然后在dfs搜索的过程中搜索与回溯的过程相当于一个栈而子节点在栈中永远在父节点的上方 那么一个强连通分量的根节点在栈中时也必然在与它所有强连通的点的下方 而平时回溯时会直接退栈而我们在回溯时判断此时的节点是不是强连通分量的根节点 是 将当前点和在当前点之上的所有点取出 这些点共同构成一个强连通分量 不是 则保留栈中节点
因为一个节点若不是强连通分量的根节点 那由它搜索下去必定与栈中的某个节点V'之间所有的节点构成一个环而环上所有点之间强连通 又因为强连通分量的根节点在栈中必然在与它所有强连通的点下方故V'便是此时这个节点所在强连通分量的根节点 而且由以上操作可知留在栈中的点属于某个以栈中某个点为根节点的强连通分量 同时由dfs特性知回溯到某个强连通分量的根节点时栈中在它之上的点不可能属于此根节点之下的强连通分量否则说明该节点不是根节点因为它的子节点可以与父节点或祖先节点相连
具体代码实现时可以维护一个Low[V] Low[V]记录的是V所属于的强连通分量的根节点的dfs序 由dfs序可知强连通分量的根节点的dfs序是整个强连通分量中最小的 那么搜索完后只需要判断Low[V]是否等于V的dfs序即可知V是否为强连通分量的根节点 而显然Low[V]=min(Low[to],Low[V]),to∈V的子节点 而当V连接的是已经在栈中的点V'时则Low[V]=min(Low[V],V'的dfs序)
算法时间复杂度:
显然Tarjan算法中每一点都只会进栈一次出栈一次 而每一个节点都会遍历它的所有边 故Tarjan算法求有限图中的强连通分量的时间复杂度为T(n+m)
代码以后补齐:
Tarjan算法初探 (1):Tarjan如何求有向图的强连通分量的更多相关文章
- 图论-求有向图的强连通分量(Kosaraju算法)
求有向图的强连通分量 Kosaraju算法可以求出有向图中的强连通分量个数,并且对分属于不同强连通分量的点进行标记. (1) 第一次对图G进行DFS遍历,并在遍历过程中,记录每一个点的退出顺序 ...
- Tarjan算法 求 有向图的强连通分量
百度百科 https://baike.baidu.com/item/tarjan%E7%AE%97%E6%B3%95/10687825?fr=aladdin 参考博文 http://blog.csdn ...
- Tarjan算法求有向图的强连通分量
算法描述 tarjan算法思想:从一个点开始,进行深度优先遍历,同时记录到达该点的时间(dfn记录到达i点的时间),和该点能直接或间接到达的点中的最早的时间(low[i]记录这个值,其中low的初始值 ...
- tarjan算法(割点/割边/点连通分量/边连通分量/强连通分量)
tarjan算法是在dfs生成一颗dfs树的时候按照访问顺序的先后,为每个结点分配一个时间戳,然后再用low[u]表示结点能访问到的最小时间戳 以上的各种应用都是在此拓展而来的. 割点:如果一个图去掉 ...
- (转)求有向图的强连通分量个数(kosaraju算法)
有向图的连通分量的求解思路 kosaraju算法 逛了很多博客,感觉都很难懂,终于找到一篇能看懂的,摘要记录一下 原博客https://www.cnblogs.com/nullzx/p/6437926 ...
- 【数据结构】DFS求有向图的强连通分量
用十字链表结构写的,根据数据结构书上的描述和自己的理解实现.但理解的不透彻,所以不知道有没有错误.但实验了几个都ok. #include <iostream> #include <v ...
- 求有向图的强连通分量个数 之 Kosaraju算法
代码: #include<cstdio> #include<cstring> #include<iostream> using namespace std; ][] ...
- Tarjan算法初探(2):缩点
接上一节 Tarjan算法初探(1):Tarjan如何求有向图的强连通分量 Tarjan算法一个非常重要的应用就是 在一张题目性质在点上性质能够合并的普通有向图中将整个强连通分量视作一个点来把整张图变 ...
- 图->连通性->有向图的强连通分量
文字描述 有向图强连通分量的定义:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly co ...
随机推荐
- 【Android】RxJava的使用(三)转换——map、flatMap
前两篇Android RxJava的使用(一)基本用法.Android RxJava的使用(二)Action介绍了RxJava的基本用法,对Rxjava还不了解的请先看以上两篇.这篇为大家讲解RxJa ...
- srop实战
前言 srop 的作用比较强,在条件允许的情况下,尽量使用它.题目来自于 i春秋的一个比赛. 题目链接: https://gitee.com/hac425/blog_data/blob/master/ ...
- linux 命令及配置文件搜索命令which、whereis
which /usr/bin/which 搜索命令所在目录及别名信息 which lsalias ls='ls --color=auto'/usr/bin/ls which rmalias rm='r ...
- oracle 手动打jar 包
1.到loracle 的安装目录,D:\ProgramFiles\oracle\product\11.2.0\dbhome_1\jdbc\lib,找到文件 ojdbc6.jar,复制到 D 盘. 2. ...
- frame shiro 认证示例及原理简述
shiro 认证流程 1.创建一个 javaSE 的maven项目(quickstart),并添加依赖 <dependency> <groupId>junit</grou ...
- 回归JavaScript基础(八)
主题:引用类型包装类.单体内置对象的介绍. 对于我们开发人员来说,JavaScript有种引用类型一定很陌生!那就是基本包装类型:Boolean.Number和String.这也不是我们的错,主要这些 ...
- springboot学习入门之五---开发Web应用之JSP篇
转载:http://tengj.top/2017/03/13/springboot5/ 1整体结构 整体的框架结构,跟前面介绍Thymeleaf的时候差不多,只是多了webapp这个用来存放jsp的目 ...
- 应用程序-特定 权限设置并未向在应用程序容器 不可用 SID (不可用)中运行的地址 LocalHost (使用 LRPC) 中的用户
这是安装biztalk server 2013出现的问题,很多天了没解决,下边这个解决办法也搜到过类似的,但上次实验时出现设置组件权限时发现都是按钮都是灰的,无法操作. 这次设置好了.谢谢ibg. 文 ...
- c++ thread 使用不当导致的崩溃问题
看个例子 class CTimer{ public: // 析构函数 virtual ~CTimer(){ } // 开始 void start() { b_exit = false; i = ; t ...
- AOP的本质
AOP的本质是HOOK: HOOK的本质是:新函数包含原函数或新函数替换原函数: 需要解决的问题: 1.新函数的生成: 2.新函数的调用机制: 3.原函数的调用机制: 新函数的生成: 1.将已有的动态 ...