Strongly Connected Components

由于是临时复习,所以会很简略

tarjan 求强连通分量

首先可以对图dfs搜索,得到一棵搜索树。

考虑在搜索过程魔改一下dfs来求强连通分量。

搜索的时候我们会遇到很多非树边,而强连通分量的产生显然和这些非树边有关系。

dfn的解释略。

每次访问到一个节点把他加入到一个栈中。

用 $low_{u}$ 表示节点 $u$ 能到达的最小的并且在栈中的 $dfn_{v}$。

考虑怎么求。

如果当前的 $v$ 未访问,那么 $v$ 能到达的点肯定都能更新 $low_{u}$,所以 $low_{u} = \min(low_{u}, low_{v})$。

如果访问过,那么看是否在栈中(根据定义),如果在,那么显然是 $low_{u} = \min(low_{u}, dfn_{v})$。

这个时候如果发现一个点 $u$,它的 $dfn_{u} = low_{u}$,那么它肯定是会产生一个新的强连通分量的,因为无论怎么走它都都和 $dfn$ 更小的节点不连通。

现在想一下它和哪些点同属于一个强连通分量。

假设现在考虑的是目前搜到的第一个强连通分量,那么显然是当前栈中的所有节点。

可以用反证法证明。

然后把这些点从栈中弹出。

如果搜到了下一个强连通分量,那肯定不会包含上一个强连通分量的点,同样是当前栈中的所有节点。

所以这同时解释了为什么 $low$ 的定义要看节点是否在栈中。

Code:

//因为太难看所以就把模板删掉了qwq
int n, m, u, v, cnt, scccnt, top, back, ans, q[10001], st[10001], dfn[10001], low[10001], a[10001], sum[10001], scc[10001], d[10001], dp[10001];
vector<int> g[10001], e[10001];
set<int> edge[10001];
void tarjan(int now) {
    low[now] = dfn[now] = ++cnt;
    st[++top] = now;
    fo(i, g[now]) {
        if(!dfn[i]) {
            tarjan(i);
            low[now] = min(low[now], low[i]);
        }
        else if(!scc[i]) low[now] = min(low[now], dfn[i]);
    }
    if(dfn[now] == low[now]) {
        scc[now] = ++scccnt;
        sum[scccnt] += a[now];
        while(st[top] != now) {
            scc[st[top]] = scccnt;
            sum[scccnt] += a[st[top]];
            --top;
        }
        --top;
    }
}
int main() {
    read(n, m);
    fu(i, 1, n) read(a[i]);
    while(m--) {
        read(u, v);
        g[u].push_back(v);
    }
    fu(i, 1, n) {
        if(!scc[i]) {
            tarjan(i);
        }
    }
    fu(i, 1, n) {
        fo(j, g[i]) {
            if(scc[i] != scc[j] && !edge[scc[i]].count(scc[j])) {
                e[scc[i]].push_back(scc[j]);
                edge[scc[i]].insert(scc[j]);
                ++d[scc[j]];
            }
        }
    }
    fu(i, 1, scccnt) {
        if(!d[i]) q[++back] = i;
    }
    fu(front, 1, back) {
        u = q[front];
        dp[u] += sum[u];
        ans = max(ans, dp[u]);
        fo(i, e[u]) {
            dp[i] = max(dp[i], dp[u]);
            if(!(--d[i])) q[++back] = i;
        }
    }
    write(ans);
    flush();
    return 0;
}
posted @ 2023-10-20 17:19  A_box_of_yogurt  阅读(1)  评论(0编辑  收藏  举报  来源
Document