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)。

  • 相关阅读:
    debian 9安装细节
    gnome环境设置
    Linux之crontab定时任务
    独显切换进入图形界面思路
    pycharm多行注释
    如何在cmd中运行.py文件
    如何在 PyCharm 中设置 Python 代码模板
    在R中使用Keras和TensorFlow构建深度学习模型
    kubernetes cert-manager installation
    Simple way to create a tunnel from one local port to another?
  • 原文地址:https://www.cnblogs.com/demian/p/9221406.html
Copyright © 2011-2022 走看看