bzoj 1051 受欢迎的牛
题目大意:
现在有N头牛,给一个 A B 表示牛A认为牛B受欢迎
这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少牛被所有的牛认为是受欢迎的
View Code
思路:
先用tarjan把每个强连通分量缩点
然后脑补一下
可以发现如果有大于一个连通分量出度为零,则不可能有解 因为这几个出度为零部分的牛互相不能认为对方受欢迎
所以只有当所有强连通分量只有一个出度为零的时候 解为那个连通分量的大小
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 #include<cmath>
5 #include<cstring>
6 #include<cstdlib>
7 #include<set>
8 #include<map>
9 #include<vector>
10 #include<stack>
11 #include<queue>
12 #define ll long long
13 #define inf 2147383611
14 #define MAXN 100100
15 #define MOD 5050
16 using namespace std;
17 inline int read()
18 {
19 int x=0,f=1;
20 char ch;ch=getchar();
21 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
22 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
23 return x*f;
24 }
25 int n,m,next[MAXN*2],first[MAXN],to[MAXN*2],cnt;
26 int Next[MAXN*2],First[MAXN],To[MAXN*2],otd[MAXN];
27 int scc,dfn[MAXN],low[MAXN],bl[MAXN],stp,num[MAXN];
28 bool vis[MAXN];
29 int st[MAXN],top;
30 void add(int u,int v) {next[++cnt]=first[u],first[u]=cnt,to[cnt]=v;}
31 void ADD(int u,int v) {Next[++cnt]=First[u],First[u]=cnt,To[cnt]=v;otd[u]++;}
32 void tarjan(int x)
33 {
34 low[x]=dfn[x]=++stp,st[++top]=x,vis[x]=1;
35 for(int i=first[x];i;i=next[i])
36 {
37 if(!dfn[to[i]])
38 {
39 tarjan(to[i]);low[x]=min(low[x],low[to[i]]);
40 }
41 else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);
42 }
43 if(low[x]==dfn[x])
44 {
45 scc++;
46 while(st[top+1]!=x) bl[st[top]]=scc,num[scc]++,vis[st[top]]=0,top--;
47 }
48 }
49 void rebuild()
50 {
51 cnt=0;
52 for(int i=1;i<=n;i++)
53 for(int j=first[i];j;j=next[j])
54 if(bl[i]!=bl[to[j]]) ADD(bl[i],bl[to[i]]);
55 }
56 int main()
57 {
58 n=read(),m=read();
59 int a,b;
60 while(m--)
61 {
62 a=read(),b=read();
63 add(a,b);
64 }
65 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
66 rebuild();
67 cnt=0;int k;
68 for(int i=1;i<=scc;i++) if(!otd[i]) {cnt++;k=i;}
69 if(cnt==1) printf("%d",num[k]);
70 else printf("0");
71 }