zoukankan      html  css  js  c++  java
  • 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)

    一个顶点u是割点,当且仅当满足(1)或(2)

    (1) u为树根,且u有多于一个子树。

    (2) u不为树根,且满足存在(u,v)为树枝边(或称父子边,即u为v在搜索树中的父亲),使得DFN(u)<=Low(v)。即:若某点的子树们能回到的点大于等于自己,则该点为割点

    一条无向边(u,v)是,当且仅当(u,v)为树枝边,且满足DFN(u)<Low(v)。

  • 相关阅读:
    电路原理图分析
    GPIO学习——用户空间操作
    在Android上运行Java和C程序
    Android命令行工具学习总结
    Android蓝牙学习笔记
    33 把数组排成最小的数
    233 Number of Digit One
    32 从1到n整数中1出现的次数
    31 连续子数组的最大和
    《大型网站技术架构》学习笔记
  • 原文地址:https://www.cnblogs.com/demian/p/9221406.html
Copyright © 2011-2022 走看看