• 强连通分量入度和出度


    题目猛戳这里

    不过以我的英语水平也看不懂。。  

    百度 翻译

    每个学校都可以把软件复制好,交给它名单上的学校。

    问题A:把软件复制成几份,然后交给不同的学校,所有学校才能够都有软件。

    问题B:添加几条边,能使得这个图变成强连通图。

    思路:

    找出所有的强连通分量,然后缩点,变成一个新有向无环图,求每个强连通分量的入度和出度。

    A:入度是0的点就是复制的最小数量,因为只要给强连通分量一个软件,他就会传到每个点,所以找出没有入口的强连通分量的数量就是要复制的数量(其他强连通分量都可以由这些分量传递过去)。

    B:in0为入度为0点的数量,out0出度为0的点的数量,添加的边的数量是=max(in0,out0);这个不好证明,但画一下图,自己理解一下,也是很容易理解的。

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <cstdio>
    #include <vector>
    #include <string>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    
    #define INF 0x3f3f3f3f
    #define MAXN 100005
    
    using namespace std;
    
    struct Edge {
        int next;
        int to;
    }edge[MAXN];
    
    int in[MAXN];
    int out[MAXN];
    int low[MAXN];
    int dfn[MAXN];
    int vis[MAXN];
    int from[MAXN];
    int belong[MAXN];
    int cnt_1;
    int cnt_2;
    int cnt_3;
    stack<int> s1;
    int N;
    int mx1, mx2;
    
    void init(void) {
        memset(in, 0, sizeof(in));
        memset(out, 0, sizeof(out));
        memset(low, 0, sizeof(low));
        memset(dfn, 0, sizeof(dfn));
        memset(vis, 0, sizeof(vis));
        memset(from, 0, sizeof(from));
        memset(belong, 0, sizeof(belong));
        cnt_1 = 0;
        cnt_2 = 0;
        cnt_3 = 0;
        mx1 = 0;
        mx2 = 0;
        while (s1.size())
            s1.pop();
    }
    
    void add(int x, int y) {
        edge[++cnt_1].next = from[x];
        edge[cnt_1].to = y;
        from[x] = cnt_1;
    }
    
    void tarjan(int x) {
        s1.push(x);
        vis[x] = 1;
        dfn[x] = low[x] = ++cnt_2;
        for (int j = from[x]; j; j = edge[j].next) {
            int k = edge[j].to;
            if (!dfn[k]) {
                tarjan(k);
                low[x] = min(low[x], low[k]);
            }
            else if (vis[k] && dfn[k] < low[x])
                low[x] = dfn[k];
        }
        if (dfn[x] == low[x]) {
            int temp;
            cnt_3++;
            do{
                temp = s1.top();
                s1.pop();
                vis[temp] = 0;
                belong[temp] = cnt_3;
            } while (temp != x);
        }
    }
    
    void f1(void) {
    
        for (int i = 1; i <= N; i++) {
            for (int j = from[i]; j; j = edge[j].next) {
                int k = edge[j].to;
                if (belong[i] != belong[k]) {
                    ++in[belong[k]];
                    ++out[belong[i]];
                }
            }
        }
    
        for (int i = 1; i <= cnt_3; i++) {
            if (!in[i])
                mx1++;
            if (!out[i])
                mx2++;
        }
    }
    
    int main()
    {
        //freopen("data.txt", "r", stdin);
        int T;
        while (~scanf("%d",&N)) {
            init();
            int a;
            for (int i = 1; i <= N; i++) {
                while (scanf("%d",&a)) {
                    if (!a)
                        break;
                    add(i, a);
                }
                
            }
            for (int i = 1; i <= N; i++) {
                if(!dfn[i])
                    tarjan(i);
            }
            f1();
            if (cnt_3 == 1)
                printf("1
    0
    ");
            else {
                /*cout << mx1 << endl;
                cout << max(mx1, mx2) << endl;*/
                printf("%d
    %d
    ", mx1, max(mx1, mx2));
            }
        }
        
    
        //freopen("CON", "r", stdin);
        //system("pause");
        return 0;
    }
  • 相关阅读:
    CF869E The Untended Antiquity 解题报告
    Walk 解题报告
    CF911F Tree Destruction 解题报告
    P4397 [JLOI2014]聪明的燕姿
    洛谷 P2329 [SCOI2005]栅栏 解题报告
    洛谷 P3747 [六省联考2017]相逢是问候 解题报告
    set-erase
    set-empty
    set-empty
    set-end
  • 原文地址:https://www.cnblogs.com/Y-is-sunshine/p/11216895.html
Copyright © 2020-2023  润新知