Tarjan算法【强连通分量】

转自:byvoid:有向图强连通分量的Tarjan算法

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

有两个概念:1.时间戳,2.追溯值

时间戳是dfs遍历节点的次序。

定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的栈中节点最小的次序号。由定义可以得出:

1 Low(u)=min{
2     DFN(u),   // 自己的次序号
3     Low(v),   //(u,v)为树枝边,u为v的父节点
4     DFN(v),   //(u,v)为指向栈中节点的后向边(非横叉边)
5 }

即以下节点的最小值:

1. 自己、子树节点的次序号

2. 指向栈中节点(后向边节点)的次序号[等价于 DFN(v)<DFN(u)且v不为u的父亲节点],这里不是横叉边(指向不在栈中的节点)。

DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。

伪码:

 1 tarjan(u)
 2 {
 3     DFN[u]=Low[u]=++Index     // 为节点u设定次序编号和Low初值
 4     Stack.push(u)             // 将节点u压入栈中
 5     for each (u, v) in E      // 枚举每一条邻边
 6         if (v is not visted)  // 如果节点v未被访问过
 7             tarjan(v)         // 继续向下找
 8             Low[u] = min(Low[u], Low[v])     
 9         else if (v in S)      // 如果节点v还在栈内
10             Low[u] = min(Low[u], DFN[v])
11     if (DFN[u] == Low[u])     // 如果节点u是强连通分量的根
12         repeat
13             v = S.pop         // 将v退栈,为该强连通分量中一个顶点
14             print v
15         until (u== v)
16 }

运行Tarjan算法的过程中,每个顶点都被访问了一次,且只进出了一次堆栈,每条边也只被访问了一次,所以该算法的时间复杂度为O(N+M)

扫描二维码关注公众号,回复: 1738917 查看本文章

猜你喜欢

转载自www.cnblogs.com/demian/p/9221406.html
今日推荐