此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。
题目链接:https://www.luogu.org/problem/show?pid=2835
题目描述
在JSOI2005夏令营快要结束的时候,很多营员提出来要把整个夏令营期间的资料刻录成一张光盘给大家,以便大家回去后继续学习。组委会觉得这个主意不错!可是组委会一时没有足够的空光盘,没法保证每个人都能拿到刻录上资料的光盘,又来不及去买了,怎么办呢?!
组委会把这个难题交给了LHC,LHC分析了一下所有营员的地域关系,发现有些营员是一个城市的,其实他们只需要一张就可以了,因为一个人拿到光盘后,其他人可以带着U盘之类的东西去拷贝啊!
可是,LHC调查后发现,由于种种原因,有些营员并不是那么的合作,他们愿意某一些人到他那儿拷贝资料,当然也可能不愿意让另外一些人到他那儿拷贝资料,这与我们JSOI宣扬的团队合作精神格格不入!!!
现在假设总共有N个营员(2<=N<=200),每个营员的编号为1~N。LHC给每个人发了一张调查表,让每个营员填上自己愿意让哪些人到他那儿拷贝资料。当然,如果A愿意把资料拷贝给B,而B又愿意把资料拷贝给C,则一旦A获得了资料,则B,C都会获得资料。
现在,请你编写一个程序,根据回收上来的调查表,帮助LHC计算出组委会至少要刻录多少张光盘,才能保证所有营员回去后都能得到夏令营资料?
输入输出格式
输入格式:先是一个数N,接下来的N行,分别表示各个营员愿意把自己获得的资料拷贝给其他哪些营员。即输入数据的第i+1行表示第i个营员愿意把资料拷贝给那些营员的编号,以一个0结束。如果一个营员不愿意拷贝资料给任何人,则相应的行只有1个0,一行中的若干数之间用一个空格隔开。
输出格式:一个正整数,表示最少要刻录的光盘数。
输入输出样例
输入样例#1:5输出样例#1:
2 3 4 0
4 5 0
0
0
1 0
1
分析:
Tarjan缩点,然后记录每个强连通分量的入度。入度为0的点的数量就是最终答案。
数组要开大一点...边最多可以有接近40000条。
以及听说数据卡快读(很可能是数据出错了但是一直没改),改用scanf吧。
AC代码:
1 #include<cstdio>
2 #include<algorithm>
3 #include<cmath>
4 #include<cstring>
5 #include<iostream>
6 #include<stack>
7
8 const int MAXN = 1005;
9
10 int n,f,t,cnt,dfn_cnt,part,ans;
11 int head[MAXN<<6],dfn[MAXN],low[MAXN];
12 int belong[MAXN],sum[MAXN],in[MAXN];
13
14 struct Edge
15 {
16 int f,t,nxt;
17 }e[MAXN<<6];
18
19 inline void insert(int f,int t)
20 {
21 e[++cnt].f = f,e[cnt].t = t;
22 e[cnt].nxt = head[f],head[f] = cnt;
23 }
24
25 inline int Min(int a,int b)
26 {return a<b?a:b;}
27
28 std::stack <int> s;
29
30 void Tarjan(int u)
31 {
32 s.push(u);
33 dfn_cnt ++;
34 dfn[u] = low[u] = dfn_cnt;
35
36 for(int i = head[u];i;i = e[i].nxt)
37 {
38 int v = e[i].t;
39 if(!dfn[v]){
40 Tarjan(v);
41 low[u] = Min(low[u],low[v]);
42 }
43
44 else if(!belong[v])
45 low[u] = Min(low[u],dfn[v]);
46 }
47
48 if(dfn[u] == low[u])
49 {
50 ++ part;
51 while(!s.empty())
52 {
53 int x = s.top();
54 s.pop();
55 belong[x] = part;
56 sum[part] ++;
57 if(x == u) break;
58 }
59 }
60 }
61
62 int main()
63 {
64 scanf("%d",&n);
65 for(int i = 1;i <= n;++ i)
66 while(1)
67 {
68 scanf("%d",&t);
69 if(!t) break;
70 insert(i,t);
71 }
72 for(int i = 1;i <= n;++ i)
73 if(!dfn[i])
74 Tarjan(i);
75 for(int i = 1;i <= cnt;++ i)
76 {
77 f = e[i].f,t = e[i].t;
78 if(belong[f] != belong[t])
79 in[belong[t]] ++;
80 }
81 for(int i = 1;i <= part;++ i)
82 if(!in[i]) ans ++;
83 printf("%d\n",ans);
84 return 0;
85 }