zoukankan      html  css  js  c++  java
  • 算法笔记——强联通分量&缩点

    强联通分量(Strongly Connected Components):有向图的极大强连通子图。

    为了搞清楚SCC是怎么回事,我们得先明白有向图中的 44 种边。

    • A. 树枝边:DFS树上的边,即指向未访问过节点的边
    • B. 前向边:指向DFS树中子树中节点的边
    • C. 后向边:指向DFS树中父亲的边
    • D. 横叉边:其他边,即指向DFS树中非子树的边

    在这里插入图片描述
    我们需要维护 22 个东西

    • 一个是 dfndfn 就是 dfsdfs 序,也是我们常说的时间戳。
    • 一个是 lowlow 就是这个点所能到达子树中的,深度最小的点祖先的dfs序编号。

    dfndfn 处理起来很简单,直接 dfsdfs 的时候编一下号就行了。

    lowlow 的初始值为 dfndfn

    对于边(u,v)

    • 若为树枝边,则用low[v]更新
    • 若为前向边,因为指向的点的信息已经通过树枝边传递过来,所以无需更新
    • 若为后向边,则用dfn[v]更新
    • 若为横叉边,则指向另一个强连通分量,无需更新

    代码:

    int s[MAXN], stop;
    int dfn[MAXN], low[MAXN];
    int scccnt, sccnum[MAXN];
    int dfscnt;
    
    inline void tarjan(int now){
        dfn[now] = low[now] = ++dfscnt;
        s[stop++] = now;
        for (int i = he[now]; i != 0 ; i = ne[i]){
            if (!dfn[ed[i]]) {
                tarjan(ed[i]);
                low[now] = min(low[now], low[ed[i]]);
            } else if(!sccnum[ed[i]]) {
                low[now] = min(low[now], dfn[ed[i]]);
            }
        }
    
        if (dfn[now] == low[now]) {
            scccnt++;
            do {
                sccnum[s[--stop]] = scccnt;
            } while(s[stop] != now);
        }
    }
    
    

    sccnum这里是维护了一个栈,判断横插边。

    例题:

  • 相关阅读:
    君のことが好きだよ。
    [拓展Bsgs] Clever
    同余方程笔记
    [HAOI2008] 糖果传递
    [USACO10DEC] Treasure Chest
    [APIO2007] 风铃
    Luogu_2015 二叉苹果树
    关于高精度
    关于博弈论
    关于DP和背包
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/12816967.html
Copyright © 2011-2022 走看看