题意:有 n 个学校每个学校可以将自己的软件共享给其他一些学校,首先,询问至少将软件派发给多少学校能够使软件传播到所有学校,其次,询问添加多少学校共享关系可以使所有学校的软件能够相互传达。
首先,第一个问题首先就做强连通缩点,对于缩点后的图询问有多少点的入度为 0,因为入度为 0 的分量必然不能通过其他点传达到。第二个问题则是询问入度为 0 和出度为 0 的点个数的最大值。
1 #include<stdio.h>
2 #include<string.h>
3 #include<stack>
4 #include<queue>
5 using namespace std;
6
7 const int maxn=100;
8 const int maxm=1e4+5;
9
10 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];
11 int n,t,scccnt;
12 int stx[maxn],low[maxn],scc[maxn];
13 int id[maxn],od[maxn];
14 stack<int>S;
15
16 int max(int a,int b){return a>b?a:b;}
17
18 void init(){
19 memset(head,-1,sizeof(head));
20 size[0]=size[1]=0;
21 memset(id,0,sizeof(id));
22 memset(od,0,sizeof(od));
23 }
24
25 void add(int a,int b,int c=0){
26 point[c][size[c]]=b;
27 nxt[c][size[c]]=head[c][a];
28 head[c][a]=size[c]++;
29 }
30
31 void dfs(int s){
32 stx[s]=low[s]=++t;
33 S.push(s);
34 for(int i=head[0][s];~i;i=nxt[0][i]){
35 int j=point[0][i];
36 if(!stx[j]){
37 dfs(j);
38 low[s]=min(low[s],low[j]);
39 }
40 else if(!scc[j]){
41 low[s]=min(low[s],stx[j]);
42 }
43 }
44 if(low[s]==stx[s]){
45 scccnt++;
46 while(1){
47 int u=S.top();S.pop();
48 scc[u]=scccnt;
49 if(s==u)break;
50 }
51 }
52 }
53
54 void setscc(){
55 memset(stx,0,sizeof(stx));
56 memset(scc,0,sizeof(scc));
57 t=scccnt=0;
58 for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
59 for(int i=1;i<=n;++i){
60 for(int j=head[0][i];~j;j=nxt[0][j]){
61 int k=point[0][j];
62 if(scc[i]!=scc[k]){
63 add(scc[i],scc[k],1);
64 od[scc[i]]++;
65 id[scc[k]]++;
66 }
67 }
68 }
69 }
70
71 int main(){
72 scanf("%d",&n);
73 init();
74 for(int i=1;i<=n;++i){
75 int b;
76 while(scanf("%d",&b)&&b){
77 add(i,b);
78 }
79 }
80 setscc();
81 int in=0,out=0;
82 for(int i=1;i<=scccnt;++i){
83 if(!id[i])in++;
84 if(!od[i])out++;
85 }
86 printf("%d\n%d\n",in,scccnt==1?0:max(in,out));
87 return 0;
88 }