Tarjan 算法

Taijan算法是求有向图强连通分量的算法。

 Tarjan 算法主要是在 DFS 的过程中维护了一些信息:dfn、low 和一个栈。

  1.  栈里存放当前已经访问过但是没有被归类到任一强连通分量的结点。
  2. dfn[u] 表示 DFS 第一次搜索到 u 的次序。
  3. Low(u) 记录该点所在的强连通子图所在子树的根节点的 Dfn 值。

基本思路:

  在深度搜索中会搜索到已访问的节点,产生环,即连通分量的一部分, 环与环的并集仍是连通分量。

  由于深度搜索总是会回溯,所以将强连通图中最早搜索到的节点认为是根节点,它的dfn 和 low都是最小的。

之后会深度搜索子树的所有节点, 确定所有与回边相关的环,在出现环时, 环上的节点的值就会统一为环上最小的值。

直到回溯到根节点 dfn = low 的标志, 输出连通分量, 其他节点low相同, 但dfn要比根节点大。

  至于( u, v )访问到新的节点,在初始化下 v 的 low 值是递增的 , 但是 v 在进入深度搜索后,它返回的值会变化。

当 v 出现在环中被处理了, v 的 low 值会变小。此时 u 也一定在环中 , v 的low 值变小, 是由于有一条回边连接到的 u 的父辈的节点

, 父辈的节点 - 顶点 - u - v - 父辈的节点 构成了一个环。

伪码解析:

Tarjan(u)

{

    DFN[u]=Low[u]=++Index               // 为节点u递增地设定次序编号和Low初值

    Stack.push(u)                                // 存放已经访问过但没有被归类到任一强连通分量的结点

    for each (u, v) in E                         //深度搜索

        if ( v is not visted ) {      

     Tarjan( v )               

             Low [ u ] = min( Low[ u ] , Low[ v ]  );   //  初始化下 low[ v ] 比较大, 若 low [ v ]变小 , v 在环中,u 也在环中, 且两个环相连通。  

  }

        else if (v in S)                       // 如果节点v还在栈内,出现回边,出现环

            Low [ u ] = min( Low[ u ], DFN[ v ] )     

    if (DFN[u] == Low[u])                       // 如果节点u是强连通分量的根

            v = S.pop                       // 将v退栈,                                                                                                                                                                           

            print v

        until (u== v)

}

 

posted on 2018-02-04 21:14  焚香谷  阅读(154)  评论(0编辑  收藏  举报