题目猛戳这里

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

百度 翻译

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

问题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\n0\n");
        else {
            /*cout << mx1 << endl;
            cout << max(mx1, mx2) << endl;*/
            printf("%d\n%d\n", mx1, max(mx1, mx2));
        }
    }
    

    //freopen("CON", "r", stdin);
    //system("pause");
    return 0;
}