出处:http://blog.csdn.net/xinghongduo/article/details/6195337

  说到以Tarjan命名的算法,我们经常提到的有3个,其中就包括本文所介绍的求强连通分量的Tarjan算法。而提出此算法的普林斯顿大学的Robert E Tarjan教授也是1986年的图灵奖获得者(具体原因请看本博“历届图灵奖得主”一文)。

首先明确几个概念。

  1. 强连通图。在一个强连通图中,任意两个点都通过一定路径互相连通。比如图一是一个强连通图,而图二不是。因为没有一条路使得点4到达点1、2或3。
  2. 强连通分量。在一个非强连通图中极大的强连通子图就是该图的强连通分量。比如图三中子图{1,2,3,5}是一个强连通分量,子图{4}是一个强连通分量。

关于Tarjan算法的伪代码和流程演示请到我的115网盘下载网上某大牛写的Doc(地址:http://u.115.com/file/f96af404d2<Tarjan算法.doc>)本文着重从另外一个角度,也就是针对tarjan的操作规则来讲解这个算法。

其实,tarjan算法的基础是DFS。我们准备两个数组Low和Dfn。Low数组是一个标记数组,记录该点所在的强连通子图所在搜索子树的根节点的Dfn值(很绕嘴,往下看你就会明白),Dfn数组记录搜索到该点的时间,也就是第几个搜索这个点的。根据以下几条规则,经过搜索遍历该图(无需回溯)和对栈的操作,我们就可以得到该有向图的强连通分量。

  1. 数组的初始化:当首次搜索到点p时,Dfn与Low数组的值都为到该点的时间。
  2. 堆栈:每搜索到一个点,将它压入栈顶。
  3. 当点p有与点p’相连时,如果此时(时间为dfn[p]时)p’不在栈中,p的low值为两点的low值中较小的一个。
  4. 当点p有与点p’相连时,如果此时(时间为dfn[p]时)p’在栈中,p的low值为p的low值和p’的dfn值中较小的一个。
  5. 每当搜索到一个点经过以上操作后(也就是子树已经全部遍历)的low值等于dfn值,则将它以及在它之上的元素弹出栈。这些出栈的元素组成一个强连通分量。
  6. 继续搜索(或许会更换搜索的起点,因为整个有向图可能分为两个不连通的部分),直到所有点被遍历。

由于每个顶点只访问过一次,每条边也只访问过一次,我们就可以在O(n+m)的时间内求出有向图的强连通分量。但是,这么做的原因是什么呢?

Tarjan算法的操作原理如下:

  1. Tarjan算法基于定理:在任何深度优先搜索中,同一强连通分量内的所有顶点均在同一棵深度优先搜索树中。也就是说,强连通分量一定是有向图的某个深搜树子树。
  2. 可以证明,当一个点既是强连通子图Ⅰ中的点,又是强连通子图Ⅱ中的点,则它是强连通子图Ⅰ∪Ⅱ中的点。
  3. 这样,我们用low值记录该点所在强连通子图对应的搜索子树的根节点的Dfn值。注意,该子树中的元素在栈中一定是相邻的,且根节点在栈中一定位于所有子树元素的最下方。
  4. 强连通分量是由若干个环组成的。所以,当有环形成时(也就是搜索的下一个点已在栈中),我们将这一条路径的low值统一,即这条路径上的点属于同一个强连通分量。
  5. 如果遍历完整个搜索树后某个点的dfn值等于low值,则它是该搜索子树的根。这时,它以上(包括它自己)一直到栈顶的所有元素组成一个强连通分量。

  文章来源:http://www.cnblogs.com/saltless

转载 - Tarjan算法(求SCC)的更多相关文章

  1. tarjan算法求scc & 缩点

    前置知识 图的遍历(dfs) 强连通&强连通分量 对于有向图G中的任意两个顶点u和v存在u->v的一条路径,同时也存在v->u的路径,我们则称这两个顶点强连通.以此类推,强连通分量 ...

  2. Tarjan算法求有向图强连通分量并缩点

    // Tarjan算法求有向图强连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> #inc ...

  3. ZOJ Problem - 2588 Burning Bridges tarjan算法求割边

    题意:求无向图的割边. 思路:tarjan算法求割边,访问到一个点,如果这个点的low值比它的dfn值大,它就是割边,直接ans++(之所以可以直接ans++,是因为他与割点不同,每条边只访问了一遍) ...

  4. HDU 1269 迷宫城堡 tarjan算法求强连通分量

    基础模板题,应用tarjan算法求有向图的强连通分量,tarjan在此处的实现方法为:使用栈储存已经访问过的点,当访问的点离开dfs的时候,判断这个点的low值是否等于它的出生日期dfn值,如果相等, ...

  5. POJ 1986 Distance Queries (Tarjan算法求最近公共祖先)

    题目链接 Description Farmer John's cows refused to run in his marathon since he chose a path much too lo ...

  6. tarjan算法求LCA

    tarjan算法求LCA LCA(Least Common Ancestors)的意思是最近公共祖先,即在一棵树中,找出两节点最近的公共祖先. 这里我们使用tarjan算法离线算法解决这个问题. 离线 ...

  7. [Tarjan系列] Tarjan算法求无向图的双连通分量

    这篇介绍如何用Tarjan算法求Double Connected Component,即双连通分量. 双联通分量包括点双连通分量v-DCC和边连通分量e-DCC. 若一张无向连通图不存在割点,则称它为 ...

  8. tarjan算法求无向图的桥、边双连通分量并缩点

    // tarjan算法求无向图的桥.边双连通分量并缩点 #include<iostream> #include<cstdio> #include<cstring> ...

  9. [学习笔记] Tarjan算法求桥和割点

    在之前的博客中我们已经介绍了如何用Tarjan算法求有向图中的强连通分量,而今天我们要谈的Tarjan求桥.割点,也是和上篇有博客有类似之处的. 关于桥和割点: 桥:在一个有向图中,如果删去一条边,而 ...

随机推荐

  1. HDU 5536/ 2015长春区域 J.Chip Factory Trie

    Chip Factory Problem Description John is a manager of a CPU chip factory, the factory produces lots ...

  2. luogu2320 鬼谷子的钱袋

    题目大意 鬼谷子决定将自己的金币数好并用一个个的小钱袋装好,以便在他现有金币的支付能力下,任何数目的金币他都能用这些封闭好的小钱的组合来付账.求钱袋数最少,并且不有两个钱袋装有相同的大于1的金币数的装 ...

  3. 2017 Multi-University Training Contest - Team 1 1002&&hdu 6034

    Balala Power! Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)T ...

  4. Win7系统专栏

    1.去掉Win7快捷方式小箭头的方法如下: 使用普通方法会使系统出现异常,比如开始菜单程序无法删除.收藏夹无法展开等,网上流传使用透明图标的方法会在快捷方式上留下一块黑痣,下面的方法是小君研究出来的, ...

  5. 图结构练习—BFSDFS—判断可达性(BFS)

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2138 注意该图为有向图,1000个点应该最多有 ...

  6. 使用cnblogs发布第一篇文章,HelloWorld

    HelloWorld! 瞅瞅源码的样式,嗯,语法高亮还是可以的,辨识度还是挺高的. <!DOCTYPE html> <html> <head> <meta c ...

  7. 如何通过putty软件远程登录并且控制linux平台

    准备备工作: 下载putty远程登录软件,图标如下 打开linux主机. Linux主机准备条件: 1 配置IP ,如果大家使用虚拟机的话建议通过vm1或者vm8进行与本地真实机进行连接,同时注意要避 ...

  8. Android 复制文本内容到系统剪贴板(自由复制)

    直接上代码:(对应的类:android.content.ClipboardManager) //获取剪贴板管理器: ClipboardManager cm = (ClipboardManager) g ...

  9. 使用composer 实现自动加载

    准备工作:提前安装好composer 1.创建项目目录OOP 2.OOP目录下新建composer.json文件,composer.json是一个空json文件,代码如下: { } 3.打开控制台,进 ...

  10. for 循环练习题

    X3 * 6528 = 3X * 8256X为一个数字 填入一个数字 使等式成立 for (var x=1;x<=9&&x>0;x++) { if ((x*10+3)*65 ...