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 ...
随机推荐
- CSS的设计模式
什么是设计模式? 曾有人调侃,设计模式是工程师用于跟别人显摆的,显得高大上:也曾有人这么说,不是设计模式没用,是你还没有到能懂它,会用它的时候. 先来看一下比较官方的解释:“设计模式(Design p ...
- 多个raq导出一个excel2007中
需求描述: 客户以前通过润乾API把多个raq模板数据来导出到一个excel文件中,由于现在数据量过大一个raq数据就超过了65535,原来的2003接口已经满足不了现在的需求, ...
- Android ListView的XML属性
1.ListView的XML属性 android:divider //在列表条目之间显示的drawable或color android:dividerHeight //用来指定divider的高度 a ...
- node(3)MVC代码结构模式moogoDB的学习
---恢复内容开始--- 一.MVC代码结构模式 设计模式:观察者模式.中介者模式,这种模式,主要做的事情是处理类与类之间‘高内聚.低耦合’; 代码架构模式:MVC.MVVM.MVP Model:模型 ...
- 【转】Twitter Storm: 在生产集群上运行topology
Twitter Storm: 在生产集群上运行topology 发表于 2011 年 10 月 07 日 由 xumingming 作者: xumingming | 可以转载, 但必须以超链接形式标明 ...
- java基础(七) java四种访问权限
引言 Java中的访问权限理解起来不难,但完全掌握却不容易,特别是4种访问权限并不是任何时候都可以使用.下面整理一下,在什么情况下,有哪些访问权限可以允许选择. 一.访问权限简介 访问权限控制: ...
- PyQt4(简单界面)
import sys; from PyQt4 import QtCore, QtGui; app=QtGui.QApplication(sys.argv); widget=QtGui.QWidget( ...
- springboot学习入门之五---开发Web应用之JSP篇
转载:http://tengj.top/2017/03/13/springboot5/ 1整体结构 整体的框架结构,跟前面介绍Thymeleaf的时候差不多,只是多了webapp这个用来存放jsp的目 ...
- 第0篇 如何访问win10的C$等默认共享
近日换新机器,装了win10,但想从旧机器访问win10的\\ip\D$拷数据过去,首先发现怎么也连不上win10的共享,于是把win10防火墙中“文件和打印机共享”的“专用”(即内网)勾选上终于可以 ...
- mode="r" 和 函数末尾调用 regist()!!!!
def regist(): f = open(r"G:\课件\day09 初始函数\code\day009 初始函数\account", mode="r", e ...