Tarjan 算法

一.算法简介

Tarjan 算法一种由Robert Tarjan提出的求解有向图强连通分量的算法,它能做到线性时间的复杂度。

我们定义:

如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。

例如:在上图中,{1 , 2 , 3 , 4 } , { 5 } ,  { 6 } 三个区域可以相互连通,称为这个图的强连通分量。

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

再Tarjan算法中,有如下定义。

DFN[ i ] : 在DFS中该节点被搜索的次序(时间戳)

LOW[ i ] : 为i或i的子树能够追溯到的最早的栈中节点的次序号

当DFN[ i ]==LOW[ i ]时,为i或i的子树可以构成一个强连通分量。

二.算法图示

以1为Tarjan 算法的起始点,如图

顺次DFS搜到节点6

回溯时发现LOW[ 5 ]==DFN[ 5 ] ,  LOW[ 6 ]==DFN[ 6 ] ,则{ 5 } , { 6 } 为两个强连通分量。回溯至3节点,拓展节点4.

拓展节点1 , 发现1再栈中更新LOW[ 4 ],LOW[ 3 ] 的值为1

回溯节点1,拓展节点2

自此,Tarjan Algorithm 结束,{1 , 2 , 3 , 4 } , { 5 } ,  { 6 } 为图中的三个强连通分量。

不难发现,Tarjan Algorithm 的时间复杂度为O(E+V).

三.算法模板

 void Tarjan ( int x ) {
dfn[ x ] = ++dfs_num ;
low[ x ] = dfs_num ;
vis [ x ] = true ;//是否在栈中
stack [ ++top ] = x ;
for ( int i=head[ x ] ; i!= ; i=e[i].next ){
int temp = e[ i ].to ;
if ( !dfn[ temp ] ){
Tarjan ( temp ) ;
low[ x ] = gmin ( low[ x ] , low[ temp ] ) ;
}
else if ( vis[ temp ])low[ x ] = gmin ( low[ x ] , dfn[ temp ] ) ;
}
if ( dfn[ x ]==low[ x ] ) {//构成强连通分量
vis[ x ] = false ;
color[ x ] = ++col_num ;//染色
while ( stack[ top ] != x ) {//清空
color [stack[ top ]] = col_num ;
vis [ stack[ top-- ] ] = false ;
}
top -- ;
}
}

(完)

Tarjan 算法&模板的更多相关文章

  1. Tarjan算法(模板)

    算法思想: 首先要明确强连通图的概念,一个有向图中,任意两个点互相可以到达:什么是强连通分量?有向图的极大连通子图叫强连通分量. 给一个有向图,我们用Tarjan算法把这个图的子图(在这个子图内,任意 ...

  2. HDU 2586 ( LCA/tarjan算法模板)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意:n个村庄构成一棵无根树,q次询问,求任意两个村庄之间的最短距离 思路:求出两个村庄的LCA,d ...

  3. tarjan算法模板

    终于能自己完整的打下来 #include<cstdio> #include<cstring> #include<iostream> #include<vect ...

  4. poj1236 Tarjan算法模板 详解

    思想: 做一遍DFS,用dfn[i]表示编号为i的节点在DFS过程中的访问序号(也可以叫做开始时间)用low[i]表示i节点DFS过程中i的下方节点所能到达的开始时间最早的节点的开始时间.初始时dfn ...

  5. Tarjan算法模板(USACO03FALL受欢迎的牛)

    好文章 #include<bits/stdc++.h> using namespace std; const int N = 10010, M = 50010; int n, m; int ...

  6. 有向图的强联通分量 Tarjan算法模板

    //白书 321页 #include<iostream> #include<cstdio> #include<cstring> #include<vector ...

  7. 割点的tarjan算法模板

    基本思路: 朴素的思想是删除每一个点,然后去dfs,这样无疑会爆炸 换一种思路,怎样判断是割点呢,如果是根节点的话毫无疑问只要看子树的数目,但是如果不是根节点呢,不知大牛是怎样想到的 利用两个数组df ...

  8. POJ1236_A - Network of Schools _强连通分量::Tarjan算法

    Time Limit: 1000MS   Memory Limit: 10000K Description A number of schools are connected to a compute ...

  9. 一直想写的关于tarjan算法的理解——向struct edge大佬低头

    tarjan的算法精髓就是dfn[]和low[]数组 dfn[i]表示在该节点被搜索的次序(时间戳) low[i]表示i或i的子树可以追溯到的最早的栈中节点 判断有强连通分量的条件就是 dfn[i]= ...

随机推荐

  1. Dapper.NET 使用简单举例

    概述 Dapper是.NET下一个micro的ORM,它和Entity Framework或Nhibnate不同,属于轻量级的,并且是半自动的.也就是说实体类都要自己写.它没有复杂的配置文件,一个单文 ...

  2. js 动态时钟

    js 动态时钟 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  3. hdu 4028 2011上海赛区网络赛H dp+map离散

    一开始用搜索直接超时,看题解会的 #include<iostream> #include<cstdio> #include<map> #include<cst ...

  4. 5.linux内核模块基础,内核模块学习

    linux内核模块基础 一.定义 Linux 内核的整体结构非常庞大,其包含的组件也非常多,如何使用这些组件呢: 方法 1:把所有的组件都编译进内核文件,即:zImage 或 bzImage,但这样会 ...

  5. 封装自己的printf函数

    #include <stdio.h> #include <stdarg.h> //方式一 #define DBG_PRINT (printf("%s:%u %s:%s ...

  6. 【J2EE入门】13个规范

    看过了j2ee教学视频,真的让我痛彻心扉,那叫痛并快乐着,痛是因为看了这么长时间,自己只知道了13个规范的概念:同样,快乐也正是因为我知道了13个规范的概念,接下来就是逐项实践的学习. 看了教学视频, ...

  7. felx项目属性(二)

    order flex-grow flex-shrink flex-basis flex align-self 1.1 order css order属性规定了弹性容器中的可伸缩项目在布局时的顺序.元素 ...

  8. EL表达式详解及应用实例

    1. EL是JSP内置的表达式语言! * jsp2.0开始,不让再使用java脚本,而是使用el表达式和动态标签来替代java脚本! * EL替代的是<%= ... %>,也就是说,EL只 ...

  9. Servlet域对象ServletContext小应用------计算网站访问量

    package cn.yzu; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Servlet ...

  10. 【maven】maven各种奇葩问题

    问题1:Could not calculate build plan: Plugin org.apache... 不能成功创建maven项目 解决方法1: http://repo1.maven.org ...