• 图论——有向图强连通分量&无向图双连通分量


    有向图强连通分量


    tarjan 算法模板

    #include
    using namespace std;
    const int N = 110, M = 10010;
    int n;
    int h[N], e[M], ne[M], idx;
    int low[N], dfn[N], din[N], dout[N], timestamp, top;
    int stk[N], id[N], dcc_cnt;
    bool is_instk[N];
    
    void add(int a, int b)
    {
        e[idx] = b; ne[idx] = h[a]; h[a] = idx ++;
    }
    
    void tarjan(int u)
    {
        low[u] = dfn[u] = ++timestamp;
        stk[++top] = u;
        is_instk[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(is_instk[j])
            {
                low[u] = min(low[u], dfn[j]);
            }
        }
        if(low[u] == dfn[u])
        {
            dcc_cnt ++;
            int y;
            do{
                y = stk[top --];
                id[y] = dcc_cnt;
                is_instk[y] = false;
            }while(y != u);
        }
    }
    
    int main()
    {
        int n; cin >> n;
        memset(h, -1, sizeof(h));
        for(int i = 1; i <= n; i ++)
        {
            int x;
            while(cin >> x, x)
            {
                add(i, x);
            }
        }
        for(int i = 1; i <= n; i ++)
        {
            if(!dfn[i])
            tarjan(i);
        }
     
        for(int u = 1; u <= n; u ++)
        {
            for(int i = h[u]; ~i; i = ne[i])
            {
                int j = e[i];
                if(id[j] != id[u])
                {
                    dout[id[u]] ++;
                    din[id[j]] ++;
                }
            }
        }
        
        int a = 0, b = 0;
        for(int i = 1; i <= dcc_cnt; i ++)
        {
            if(!din[i]) a++;
            if(!dout[i]) b ++;
        }
        cout << a << endl;
        if(dcc_cnt == 1) cout << 0 << endl;
        else cout << max(a, b) << endl;
        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

    结论:

    1. 有向图最少需要加min(in, out) 边变为强连通分量
      in是入度为0的连通分量的个数
      out是出度为0的连通分量的个数

    无向图双连通分量

    无向图边的双连通分量(桥)
    #include
    using namespace std;
    const int N = 5100, M = 20100;
    int n, m; 
    int h[N], e[M], ne[M], idx;
    int low[N], dfn[N], stk[N], d[N], id[N], top, timestamp, dcc_cnt;
    bool is_bridge[M];
    
    void add(int a, int b)
    {
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx ++;
    }
    
    void tarjan(int u, int from)
    {
        dfn[u] = low[u] = ++ timestamp;
        stk[++top] = u;
        
        for(int i = h[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if(!dfn[j])
            {
                tarjan(j, i);
                low[u] = min(low[u], low[j]);
                if(dfn[u] < low[j])
                {
                    is_bridge[i] = is_bridge[i^1] = true;
                }
            }
            else if(i != (from ^ 1))
            {
                low[u] = min(low[u], dfn[j]);
            }
        }
        if(low[u] == dfn[u])
        {
            int y; ++dcc_cnt;
            do{
                y = stk[top--];
                id[y] = dcc_cnt;
            }while(y != u);
        }
    }
    
    int main()
    {
        cin >> n >> m;
        memset(h, -1, sizeof(h));
        for(int i = 1; i <= m; i ++)
        {
            int a, b; cin >> a >> b;
            add(a, b), add(b, a);
        }
        tarjan(1, -1);
        for(int i = 0; i < idx; i ++)
        {
            if(is_bridge[i])
            {
                d[id[e[i]]] ++;
            }
        }
        int ans = 0;
        for(int i = 1; i <= dcc_cnt; i ++)
        {
            if(d[i] == 1)
            {
                ans ++;
            }
        }
        cout << (ans+1)/2 << endl;
        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

    结论

    1. 把无向图变为边双连通无向图最少加缩点后叶子节点除2上取整
      res = (ans+1)/2 叶子节点就是缩点后度数唯一的连通分量
  • 相关阅读:
    R语言使用caret包的getModelInfo函数获取caret包中提供的模型算法列表
    不同路径的数目
    指令格式学习
    用HTML+CSS做一个漂亮简单的个人网页——樱木花道篮球3个页面 学生个人网页设计作品 学生个人网页模板 简单个人主页
    听GPT 讲Rust源代码--library/std(15)
    链式前向星
    城市数字孪生效果怎么样?实景三维国内公司强荐广州华锐互动
    如何快速搭建一个ssm框架
    南山区民政局关于开展2022年度南山区社会组织等级评估工作的通知
    基于深度卷积神经网络的时间序列图像分类,开源、低功耗、低成本的人工智能硬件提供者
  • 原文地址:https://blog.csdn.net/qq_63092029/article/details/132839291