P2835 刻录光盘 (tarjan缩点)

【题目描述】

    现在假设总共有N个营员(2<=N<=200),每个营员的编号为1~N。LHC给每个人发了一张调查表,让每个营员填上自己愿意让哪些人到他那儿拷贝资料。当然,如果A愿意把资料拷贝给B,而B又愿意把资料拷贝给C,则一旦A获得了资料,则B,C都会获得资料。求最小需要刻录多少张光盘。

【题目链接】

    https://www.luogu.org/problemnew/show/P2835

【算法】

    tarjan缩点再求度数为1的点的个数。缩点后,每个强连通分量视作一个点,分量内的边不考虑,其余边相当于使指向的点(分量)度数加一。

【代码】

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 struct edge{ int to,next; }e[40010];
 4 int n,tot,num,top,cnt,ans;
 5 int head[210],stk[210],low[210],dfn[210],ins[210],c[210];
 6 bool v[210];
 7 void add(int from,int to)
 8 {
 9     e[++tot].to=to,e[tot].next=head[from];
10     head[from]=tot;
11 }
12 void tarjan(int x)
13 {
14     dfn[x]=low[x]=++num;
15     stk[++top]=x,ins[x]=1;
16     for(int i=head[x];i;i=e[i].next) {
17         int to=e[i].to;
18         if(!dfn[to]) {
19             tarjan(to);
20             low[x]=min(low[to],low[x]);
21         } else if(ins[to])
22             low[x]=min(low[x],low[to]);
23     }
24     if(dfn[x]==low[x]) {
25         cnt++; int y;
26         do {
27             y=stk[top--],ins[y]=0;
28             c[y]=cnt;
29         } while(x!=y);
30     }
31 }
32 int main()
33 {
34     scanf("%d",&n);
35     for(int i=1;i<=n;i++) {
36         int a;
37         while(scanf("%d",&a)&&a) add(i,a);
38     }
39     for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
40     for(int i=1;i<=n;i++) {
41         for(int j=head[i];j;j=e[j].next) {
42             int to=e[j].to;
43             if(c[i]==c[to]) continue;
44             v[c[to]]=1;
45         }
46     }
47     for(int i=1;i<=cnt;i++)
48         if(!v[i]) ans++;
49     printf("%d\n",ans);
50     return 0;
51 }

猜你喜欢

转载自www.cnblogs.com/Willendless/p/9451523.html
今日推荐