题目猛戳这里
不过以我的英语水平也看不懂。。
百度 翻译
每个学校都可以把软件复制好,交给它名单上的学校。
问题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; }