返回顶部

模板 - 强连通缩点

https://www.acwing.com/problem/content/369/

一定要小心缩点之后只剩下一个强连通分量(一个孤立点)的时候,本身就是强连通的了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1005;
const int INF = 0x3f3f3f3f;

int n, w[MAXN];

vector<int> G[MAXN], AG[MAXN];

//从i点出发的连通分量,染色为c1[i]
int c1[MAXN], cntc1;

//i点所在的强连通分量,染色为c2[i]
int c2[MAXN], cntc2;

//第i个强连通分量内的点
vector<int> C2[MAXN];

int s[MAXN], cnts;

void dfs1(int u) {
    c1[u] = cntc1;
    for (int v : G[u])
        if (!c1[v])
            dfs1(v);
    s[++cnts] = u;
}

void dfs2(int u) {
    C2[cntc2].push_back(u);
    c2[u] = cntc2;
    for (int v : AG[u])
        if (!c2[v])
            dfs2(v);
}

void Kosaraju() {
    //再计算环
    for (int i = 1; i <= n; ++i)
        if (!c1[i]) {
            ++cntc1;
            dfs1(i);
        }
    for (int i = n; i >= 1; --i)
        if (!c2[s[i]]) {
            ++cntc2;
            dfs2(s[i]);
        }
}

set<int> AG2[MAXN], G2[MAXN];
int outdeg2[MAXN];
int indeg2[MAXN];

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    scanf("%d", &n);

    for(int i = 1; i <= n; ++i) {
        while(true) {
            int v;
            scanf("%d", &v);
            if(v == 0)
                break;
            G[i].push_back(v);
            AG[v].push_back(i);
        }
    }

    Kosaraju();

    /*for(int i = 1; i <= n; ++i) {
        printf("i=%d c2=%d\n", i, c2[i]);
    }*/

    for(int u = 1; u <= cntc2; ++u) {
        for(auto ui : C2[u]) {
            for(auto vi : G[ui]) {
                if(c2[vi] != u && !G2[u].count(c2[vi])) {
                    ++outdeg2[u];
                    ++indeg2[c2[vi]];
                    G2[u].insert(c2[vi]);
                    AG2[c2[vi]].insert(u);
                }
            }
        }
    }

    int cnt0out = 0, cnt0in = 0;
    for(int i = 1; i <= cntc2; ++i) {
        if(indeg2[i] == 0)
            ++cnt0in;
        if(outdeg2[i] == 0)
            ++cnt0out;
    }

    int ans = max(cnt0in, cnt0out);
    if(cntc2 == 1)
        ans = 0;
    printf("%d\n%d\n", cnt0in, ans);
    return 0;
}
posted @ 2019-09-27 21:23  Inko  阅读(173)  评论(0编辑  收藏  举报