算法笔记——强连通分量&缩点

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

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

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

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

  • 一个是 d f n dfn dfn 就是 d f s dfs dfs 序,也是我们常说的时间戳。
  • 一个是 l o w low low 就是这个点所能到达子树中的,深度最小的点祖先的dfs序编号。

d f n dfn dfn 处理起来很简单,直接 d f s dfs dfs 的时候编一下号就行了。

l o w low low 的初始值为 d f n dfn dfn

对于边(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这里是维护了一个栈,判断横插边。

例题:

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值