• Tarjan 求有向图的强连通分量


    重温Tarjan, 网上看了许多博客感觉都讲的不清楚. 故传上来自己的笔记, 希望帮到大家.

    提到的一些概念可以参考 oi wiki, 代码也是 oi wiki 的, 因为我不认为我能写出比大佬更好的代码了.


    强连通分量: 有向图的最大强连通子图 ( 有向图中任意两点可达 )

    • Tarjan

      1. 对每个结点维护:

        • dfn[x]: 当前节点的 dfs 序.

        • low[x]: x 向下搜索能到达的最小 dfs 序.

      2. 更新 low:

        1. v 未被访问过: 初始 low[v] = dfn[v].v 入栈. 回溯时用 low[v] 更新它的 fa 的 low[ ].

        2. v 被访问过, 且还在栈中: 用 dfs[v] 更新 fa 的 low.

        3. v 被访问过, 不在栈中: 说明这是一个 fa 到 v 的单向访问, 跳过.

      3. 获取答案:

        能让 dfn[x] > low[x], 只有当 X 的子树中某个节点 C 有{1. A2. X  xfa .

        1. 横向边: 说明 A 没有连接到 C 的边, 否则在之前 C 就被遍历了, 轮不到 X 来遍历. 就用是否 C 在栈中来排除这个情况, 子树 A 中的所有强连通分量之前已经出栈过了( 看代码的实现 ).
        2. 返祖边: 说明 xfa -> x -> c -> xfa 形成环, 在同一个强连通子图( 我们知道, 强连通图是许多环嵌套成的 ). 而且这个子图的根是 xfa 满足 dfn[xfa] = low[xfa].

        此时栈中进来过三类节点 :

        {1.  x {1.  xfa , .2. , ,  xfa ( X ),.2. x (),  x .

        故, 回溯时若节点符合 dfn[x] = low[x], 说明当前节点是它所属连通块的最小节点. 栈里它之上所有点都是一个强连通块.

    代码:

     const int Maxn = 1e5 + 10;
        
        int dfn[Maxn], low[Maxn], dfncnt, s[Maxn], in_stack[Maxn], tp;
        int scc[Maxn], sc;  // 结点 i 所在 SCC 的编号
        int sz[Maxn];       // 强连通 i 的大小
        
        void tarjan(int u) {
            low[u] = dfn[u] = ++dfncnt, s[++tp] = u, in_stack[u] = 1;
            for (int i = head[u]; i; i = eg[i].nex) {
                const int &v = eg[i].to;
                if (!dfn[v]) {
                    tarjan(v);
                    low[u] = min(low[u], low[v]);
                } else if (in_stack[v]) {
                    low[u] = min(low[u], dfn[v]);
                }
            }
            if (dfn[u] == low[u]) {
                ++sc;
                while (s[tp] != u) {
                    scc[s[tp]] = sc;
                    sz[sc]++;
                    in_stack[s[tp]] = 0;
                    --tp;
                }
                scc[s[tp]] = sc;
                sz[sc]++;
                in_stack[s[tp]] = 0;
                --tp;
            }
        }
    
  • 相关阅读:
    易基因:单细胞转录组测序(scRNA-seq)揭示猪窦卵泡细胞异质性和通讯模式|项目文章
    [算法应用]关键路径算法的简单应用
    Unity --- 脚本组件 --- 生命周期与执行顺序
    郁金香2021年游戏辅助技术中级班(六)
    MacOS如何降级旧版本?macOS降级,从 Ventura 13.0至Monterey 12
    Java的反射机制
    ES6 入门教程 16 Reflect 16.2 静态方法 & 16.3 实例:使用 Proxy 实现观察者模式
    Multiple CORS header ‘Access-Control-Allow-Origin‘ not allowed
    实现目录数据的上移(up)、下移(down)、置顶(top)、置底(bottom)的操作
    java jedis连接redis数据库实战
  • 原文地址:https://www.cnblogs.com/taulee01/p/18259333