• acwing算法提高之图论--有向图的强连通分量


    1 介绍

    本博客介绍有向图的强连通分量的题目。

    连通分量:是针对有向图的一个概念。对于分量中任意两个结点a、b,必然可以从a走到b,且从b走到a。
    强连通分量:是针对有向图的一个概念。极大强连通分量,也就是说再加一个结点,它就不是连通分量。

    强连通分量,用来将一个有向图转化为一个有向无环图(DAG、拓扑图)。方法是缩点,将所有连通分量缩成一个点。
    有向无环图有很多好处,可以递推(即拓扑序)求最短路或最长路。

    求解方法Tarjan算法

    2 训练

    题目11174受欢迎的牛

    C++代码如下,

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 10010, M = 50010;
    
    int n, m;
    int h[N], e[M], ne[M], idx;
    int dfn[N], low[N], timestamp;
    int stk[N], top;
    bool in_stk[N];
    int id[N], scc_cnt, Size[N];
    int dout[N];
    
    void add(int a, int b) {
        e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++ timestamp;
        stk[++top] = u, in_stk[u] = true;
        for (int i = h[u]; i != -1; i = ne[i]) {
            int j = e[i];
            if (!dfn[j]) {
                tarjan(j);
                low[u] = min(low[u], low[j]);
            } else if (in_stk[j]) {
                low[u] = min(low[u], dfn[j]);
            }
        }
        
        if (dfn[u] == low[u]) {
            ++scc_cnt;
            int y;
            do {
                y = stk[top--];
                in_stk[y] = false;
                id[y] = scc_cnt;
                Size[scc_cnt] ++;
            } while (y != u);
        }
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        memset(h, -1, sizeof h);
        while (m--) {
            int a, b;
            scanf("%d%d", &a, &b);
            add(a, b);
        }
        
        for (int i = 1; i <= n; ++i) {
            if (!dfn[i]) {
                tarjan(i);
            }
        }
        
        for (int i = 1; i <= n; ++i) {
            for (int j = h[i]; ~j; j = ne[j]) {
                int k = e[j];
                int a = id[i], b = id[k];
                if (a != b) dout[a]++;
            }
        }
        
        int zeros = 0, sum = 0;
        for (int i = 1; i <= scc_cnt; ++i) {
            if (!dout[i]) {
                zeros++;
                sum += Size[i];
                if (zeros > 1) {
                    sum = 0;
                    break;
                }
            }
        }
        
        printf("%d\n", sum);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    题目2367学校网络

    C++代码如下,

    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 110, M = 10010;
    
    int n;
    int h[N], e[M], ne[M], idx;
    int dfn[M], low[N], timestamp;
    int stk[N], top;
    bool in_stk[N];
    int id[N], scc_cnt;
    int din[N], dout[N];
    
    void add(int a, int b) {
        e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++ timestamp;
        stk[++top] = u, in_stk[u] = true;
        
        for (int i = h[u]; ~i; i = ne[i]) {
            int j = e[i];
            if (!dfn[j]) {
                tarjan(j);
                low[u] = min(low[u], low[j]);
            } else if (in_stk[j]) {
                low[u] = min(low[u], dfn[j]);
            }
        }
        
        if (dfn[u] == low[u]) {
            ++scc_cnt;
            int y;
            do {
                y = stk[top--];
                in_stk[y] = false;
                id[y] = scc_cnt;
            }  while (y != u);
        }
    }
    
    int main() {
        cin >> n;
        memset(h, -1, sizeof h);
        for (int i = 1; i <= n; ++i) {
            int t;
            while (cin >> t, t) add(i, t);
        }
        
        for (int i = 1; i <= n; ++i) {
            if (!dfn[i]) {
                tarjan(i);
            }
        }
        
        for (int i = 1; i <= n; ++i) {
            for (int j = h[i]; j != -1; j = ne[j]) {
                int k = e[j];
                int a = id[i], b = id[k];
                if (a != b) {
                    dout[a]++;
                    din[b]++;
                }
            }
        }
        
        int a = 0, b = 0;
        for (int i = 1; i <= scc_cnt; ++i) {
            if (!din[i]) a++;
            if (!dout[i]) b++;
        }
        
        printf("%d\n", a);
        if (scc_cnt == 1) puts("0");
        else printf("%d\n", max(a, b));
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    题目31175最大半连通子图

    C++代码如下,

    #include 
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    typedef long long LL;
    
    const int N = 100010, M = 2000010;
    int n, m, mod;
    int h[N], hs[N], e[M], ne[M], idx;
    int dfn[N], low[N], timestamp;
    int stk[N], top;
    bool in_stk[N];
    int id[N], scc_cnt, scc_size[N];
    int f[N], g[N];
    
    void add(int h[], int a, int b) {
        e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    }
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++ timestamp;
        stk[++top] = u, in_stk[u] = true;
        
        for (int i = h[u]; ~i; i = ne[i]) {
            int j = e[i];
            if (!dfn[j]) {
                tarjan(j);
                low[u] = min(low[u], low[j]);
            } else if (in_stk[j]) {
                low[u] = min(low[u], dfn[j]);
            } 
        }
        
        if (dfn[u] == low[u]) {
            ++scc_cnt;
            int y;
            do {
                y = stk[top--];
                in_stk[y] = false;
                id[y] = scc_cnt;
                scc_size[scc_cnt]++;
            } while (y != u);
        }
    }
    
    int main() {
        memset(h, -1, sizeof h);
        memset(hs, -1, sizeof hs);
        
        scanf("%d%d%d", &n, &m, &mod);
        while (m--) {
            int a, b;
            scanf("%d%d", &a, &b);
            add(h, a, b);
        }
        
        for (int i = 1; i <= n; ++i) {
            if (!dfn[i]) {
                tarjan(i);
            }
        }
        
        unordered_set<LL> S;
        for (int i = 1; i <= n; ++i) {
            for (int j = h[i]; ~j; j = ne[j]) {
                int k = e[j];
                int a = id[i], b = id[k];
                LL hash = a * 1000000ll + b;
                if (a != b && !S.count(hash)) {
                    add(hs, a, b);
                    S.insert(hash);
                }
            }
        }
        
        for (int i = scc_cnt; i; i--) {
            if (!f[i]) {
                f[i] = scc_size[i];
                g[i] = 1;
            }
            for (int j = hs[i]; ~j; j = ne[j]) {
                int k = e[j];
                if (f[k] < f[i] + scc_size[k]) {
                    f[k] = f[i] + scc_size[k];
                    g[k] = g[i];
                } else if (f[k] == f[i] + scc_size[k]) {
                    g[k] = (g[k] + g[i]) % mod;
                }
            }
        }
        
        int maxf = 0, sum = 0;
        for (int i = 1; i <= scc_cnt; ++i) {
            if (f[i] > maxf) {
                maxf = f[i];
                sum = g[i];
            } else if (f[i] == maxf) sum = (sum + g[i]) % mod;
        }
        
        printf("%d\n", maxf);
        printf("%d\n", sum);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108

    题目4368银河

    C++代码如下,

    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    typedef long long LL;
    
    const int N = 100010, M = 600010;
    int n, m;
    int h[N], hs[N], e[M], ne[M], w[M], idx;
    int dfn[N], low[N], timestamp;
    int stk[N], top;
    bool in_stk[N];
    int id[N], scc_cnt, sz[N];
    int dist[N];
    
    void add(int h[], int a, int b, int c) {
        e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
    }
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++ timestamp;
        stk[++top] = u, in_stk[u] = true;
        
        for (int i = h[u]; ~i; i = ne[i]) {
            int j = e[i];
            if (!dfn[j]) {
                tarjan(j);
                low[u] = min(low[u], low[j]);
            } else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
        }
        
        if (dfn[u] == low[u]) {
            ++scc_cnt;
            int y;
            do {
                y = stk[top--];
                in_stk[y] = false;
                id[y] = scc_cnt;
                sz[scc_cnt] ++;
            } while (y != u);
        }
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        memset(h, -1, sizeof h);
        memset(hs, -1, sizeof hs);
        
        for (int i = 1; i <= n; ++i) add(h, 0, i, 1);
        
        while (m--) {
            int t, a, b;
            scanf("%d%d%d", &t, &a, &b);
            if (t == 1) add(h, b, a, 0), add(h, a, b, 0);
            else if (t == 2) add(h, a, b, 1);
            else if (t == 3) add(h, b, a, 0);
            else if (t == 4) add(h, b, a, 1);
            else add(h, a, b, 0);
        }
        
        tarjan(0);
        
        bool success = true;
        for (int i = 0; i <= n; ++i) {
            for (int j = h[i]; ~j; j = ne[j]) {
                int k = e[j];
                int a = id[i], b = id[k];
                if (a == b) {
                    if (w[j] > 0) {
                        success = false;
                        break;
                    }
                } else {
                    add(hs, a, b, w[j]);
                }
            }
            if (!success) break;
        }
        
        if (!success) puts("-1");
        else {
            for (int i = scc_cnt; i; --i) {
                for (int j = hs[i]; ~j; j = ne[j]) {
                    int k = e[j];
                    dist[k] = max(dist[k], dist[i] + w[j]);
                }
            }
            
            LL res = 0;
            for (int i = 1; i <= scc_cnt; ++i) {
                res += (LL)dist[i] * sz[i];
            }
            
            printf("%lld\n", res);
        }
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
  • 相关阅读:
    传统机器学习笔记7——GBDT模型详解
    vue和react的相同点和不同点
    java操作es集群模糊查询等
    selenium.chrome怎么写扩展拦截或转发请求?
    Ubuntu 安装 GDAL C++库
    回归预测 | MATLAB实现BO-LSTM贝叶斯优化长短期神经网络多输入单输出回归预测
    INDICATOR 再c嵌入sql环境中的作用
    ElementUI浅尝辄止32:NavMenu 导航菜单
    极简试用期转正述职报告PPT模板
    使用动态住宅代理还能带来哪些好处?
  • 原文地址:https://blog.csdn.net/YMWM_/article/details/137980461