# POJ-1236 Network of Schools 【强连通分量+缩点】

Description

A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B
You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school.

Input

The first line contains an integer N: the number of schools in the network (2 <= N <= 100). The schools are identified by the first N positive integers. Each of the next N lines describes a list of receivers. The line i+1 contains the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line.

Output

Your program should write two lines to the standard output. The first line should contain one positive integer: the solution of subtask A. The second line should contain the solution of subtask B.

Sample Input

5
2 4 3 0
4 5 0
0
0
1 0

Sample Output

1
2

题解：题目比较简单，先算出强连通分量，再缩点，算出缩点后图的每个点的入度和出度，可以发现，只要给每个入度为0的点分配软件，就是最优策略（因为入度大于0的点一定可以从前一个点获得），B任务的解就是max(入度为0的点数，出度为0的点数），易知要使图强连通，尾接到头是最优方案，谁大谁就是最终解。（注意：如果强连通分量只有一个的时候一定要令ans2=0,因为那时即使所有点的入度出度虽然不为0但根据该算法是不计算，亲测不特判会WA）代码：
 1 #include<cstdio>
2 #include<iostream>
3 #include<algorithm>
4 #include<cstring>
5 #include<vector>
6 #include<set>
7 #include<queue>
8 #include<stack>
9 using namespace std;
10 #define M(a, b) memset(a, b, sizeof(a))
11 #define INF 0x3f3f3f3f
12 const int N = 100 + 5;
13 int pre[N], sccno[N], dfs_clock, scc_cnt;
14 int ind[N], od[N];
15 vector<int> G[N];
16 stack<int> S;
17
18 int dfs(int u) {
19     int lowu = pre[u] = ++dfs_clock;
20     S.push(u);
21     for (int i = 0; i < G[u].size(); ++i) {
22         int v = G[u][i];
23         if (!pre[v]) {
24             int lowv = dfs(v);
25             lowu = min(lowu, lowv);
26         }
27         else if (!sccno[v]) {
28             lowu = min(lowu, pre[v]);
29         }
30     }
31     if (lowu == pre[u]) {
32         ++scc_cnt;
33         while (true) {
34             int x = S.top(); S.pop();
35             sccno[x] = scc_cnt;
36             if (x == u) break;
37         }
38     }
39     return lowu;
40 }
41
42 void find_scc(int n) {
43     M(pre, 0); M(sccno, 0);
44     dfs_clock = scc_cnt = 0;
45     for (int i = 0; i < n; ++i)
46         if (!pre[i]) dfs(i);
47 }
48
49 int main() {
50     int n, v;
51     while (~scanf("%d", &n)) {
52         for (int u = 0; u < n; ++u) {
53             while(true) {
54                 scanf("%d", &v); --v;
55                 if (v == -1) break;
56                 G[u].push_back(v);
57             }
58         }
59         find_scc(n);
60         M(ind, 0); M(od, 0);
61         for (int u = 0; u < n; ++u)
62             for (int i = 0; i < G[u].size(); ++i) {
63                 int v = G[u][i];
64                 if (sccno[u] != sccno[v]) {
65                     od[sccno[u]]++, ind[sccno[v]]++;
66                 }
67             }
68         int in0 = 0, out0 = 0;
69         for (int i = 1; i <= scc_cnt; ++i) {
70             if (!ind[i]) in0++;
71             if (!od[i]) out0++;
72         }
73         int ans2 = max(in0, out0);
74         if (scc_cnt == 1) ans2 = 0;
75         printf("%d\n%d\n", in0, ans2);
76     }
77
78     return 0;
79 }

posted @ 2017-04-18 22:32  Robin!  阅读(...)  评论(...编辑  收藏