在此大概讲一下初学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如何求有向图的强连通分量的更多相关文章

  1. 图论-求有向图的强连通分量(Kosaraju算法)

    求有向图的强连通分量     Kosaraju算法可以求出有向图中的强连通分量个数,并且对分属于不同强连通分量的点进行标记. (1) 第一次对图G进行DFS遍历,并在遍历过程中,记录每一个点的退出顺序 ...

  2. Tarjan算法 求 有向图的强连通分量

    百度百科 https://baike.baidu.com/item/tarjan%E7%AE%97%E6%B3%95/10687825?fr=aladdin 参考博文 http://blog.csdn ...

  3. Tarjan算法求有向图的强连通分量

    算法描述 tarjan算法思想:从一个点开始,进行深度优先遍历,同时记录到达该点的时间(dfn记录到达i点的时间),和该点能直接或间接到达的点中的最早的时间(low[i]记录这个值,其中low的初始值 ...

  4. tarjan算法(割点/割边/点连通分量/边连通分量/强连通分量)

    tarjan算法是在dfs生成一颗dfs树的时候按照访问顺序的先后,为每个结点分配一个时间戳,然后再用low[u]表示结点能访问到的最小时间戳 以上的各种应用都是在此拓展而来的. 割点:如果一个图去掉 ...

  5. (转)求有向图的强连通分量个数(kosaraju算法)

    有向图的连通分量的求解思路 kosaraju算法 逛了很多博客,感觉都很难懂,终于找到一篇能看懂的,摘要记录一下 原博客https://www.cnblogs.com/nullzx/p/6437926 ...

  6. 【数据结构】DFS求有向图的强连通分量

    用十字链表结构写的,根据数据结构书上的描述和自己的理解实现.但理解的不透彻,所以不知道有没有错误.但实验了几个都ok. #include <iostream> #include <v ...

  7. 求有向图的强连通分量个数 之 Kosaraju算法

    代码: #include<cstdio> #include<cstring> #include<iostream> using namespace std; ][] ...

  8. Tarjan算法初探(2):缩点

    接上一节 Tarjan算法初探(1):Tarjan如何求有向图的强连通分量 Tarjan算法一个非常重要的应用就是 在一张题目性质在点上性质能够合并的普通有向图中将整个强连通分量视作一个点来把整张图变 ...

  9. 图->连通性->有向图的强连通分量

    文字描述 有向图强连通分量的定义:在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly co ...

随机推荐

  1. Ubuntu下彻底卸载wine

    简介: wine是linux下模拟windows的一个东西,可以用来安装exe程序,但是对于wine的卸载确 实非常麻烦的,这里是彻底卸载wine的一个教程. ##首先卸载wine sudo apt- ...

  2. Eclipse工程 导入 Android Studio

    最近Eclipse好多项目转Android Studio 百度翻看好多文章 这篇不错 特纪录下 地址:http://www.cnblogs.com/bluestorm/p/3757402.html 一 ...

  3. GDAL线面互转换(2)

    在上一个文章中介绍了线转化为面和面转化为线,其主要的实现思路就是把面中的点取出来构成线,把线中的点取出来构成面,实际上就是一个硬拷贝,无奈客户的实际需求并非如此,客户想要线转面的时候几条相交线构成面, ...

  4. PHP isset()与empty()的使用区别

    PHP的isset()函数 一般用来检测变量是否设置 格式:bool isset ( mixed var [, mixed var [, ...]] ) 功能:检测变量是否设置 返回值: 若变量不存在 ...

  5. Pig filter用法举例

    filter:过滤数据,只有符合特定条件的数据才会被保留下来,然后进入下一个数据流.   1)等值比较 filter data by $0 == 1 filter data by $0 != 1   ...

  6. git repo代码部署策略及工具

    一般在项目或者产品开发流程中,先是开发人员在本地做好开发及测试,其中可能包含很多用于测试用的目录以及源代码文件,在部署前往往会有一个build过程.web项目最终build产生出优化生产环境下减少ht ...

  7. 使用mac版思维导图软件MindNode

    下载地址 http://pan.baidu.com/s/1hq3fUVq 思维导图又叫心智图,是表达发射性思维的有效的图形思维工具 ,它简单却又极其有效,是一种革命性的思维工具.思维导图运用图文并重的 ...

  8. 多线程应用-函数方式(thread)

    多线程只能使用一颗CPU,无法发挥多核心的优势.计算密集型用python的多线程效果不明显的,I/O密集型才能看出效果,可以发挥多核优势. GIL是全局资源锁,所以,如果没有涉及到资源的调用,是不会体 ...

  9. JAVA入门之程序设计环境搭建

    这篇文章写给刚接触或者想学JAVA的新朋友.学习JAVA,需要找一本好的入门书籍,推荐<Java从入门到精通>,然后就是JAVA程序设计开发环境的搭建. 首先,我们需要安装JAVA开发工具 ...

  10. 终于明白为什么要赋值给ret ,

    def my_max(a,b): if a > b: return a else: return b my_max(10,45)# 如果只是这样,那么只是运行了并产生返回值,但没有打印返回值t ...