1051: [HAOI2006]受欢迎的牛
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1928 Solved: 1021
[ Submit][ Status]
Description
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
Input
第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)
Output
一个数,即有多少头牛被所有的牛认为是受欢迎的。
Sample Input
3 3
1 2
2 1
2 3
1 2
2 1
2 3
Sample Output
1
【数据范围】
10%的数据N<=20, M<=50
30%的数据N<=1000,M<=20000
70%的数据N<=5000,M<=50000
100%的数据N<=10000,M<=50000
【数据范围】
10%的数据N<=20, M<=50
30%的数据N<=1000,M<=20000
70%的数据N<=5000,M<=50000
100%的数据N<=10000,M<=50000
【题解】从题目所给的信息中,我们发现如果节点 i 被a[i]头奶牛欢迎,那么如果 i 认为 j 受欢迎,j 就可以得到 a[i] 的欢迎。那么如果 i 是被所有的奶牛欢迎呢?是不是 i 所认为受欢迎的奶牛都会被所有奶牛受欢迎,那么i 和 它认为受欢迎的奶牛就构成了一个强连通分量。所以整个情况就变成了,求那个强连通分量中的个数,而这个强连通分量包含的性质就是没有出度,不是吗?所以我们只要找的那个没有出度的强连通分量(注意:万一出现多个没有出度的,就说明不可能存在被所有奶牛欢迎的情况)求一下个数就可以了。
#include<cstdio>
#include<cstring>
#define maxn 20000
#define maxm 51000
int low[maxn],to[maxm],next[maxm],s[maxn],at[maxn],appear[maxn],dfn[maxn];
int high=0,tot=0,h=0,f[maxn],d[maxn],from[maxn],w=0;
inline int min(int x,int y){return x<y?x:y;}
inline void add(int x,int y)
{
to[++tot]=y;next[tot]=s[x];s[x]=tot;
}
void Tarjan(int x)
{
dfn[x]=low[x]=++high;
appear[x]=at[x]=1;
f[++h]=x;
for(int e=s[x];e;e=next[e])
if(!appear[to[e]])
{
Tarjan(to[e]);
low[x]=min(low[x],low[to[e]]);
}else if(at[to[e]])low[x]=min(low[x],dfn[to[e]]);
if(dfn[x]==low[x]){
w++;f[h+1]=-1;
while(f[h+1]!=x)
{
at[f[h]]=0;
from[f[h--]]=w;
}if(h<0)h=0;
}
}
int main()
{
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(appear,0,sizeof(appear));
memset(at,0,sizeof(at));
memset(d,0,sizeof(d));
int n,m;w=0;
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1;i<=n;i++)
if(!dfn[i])Tarjan(i);
for(int i=1;i<=n;i++)
for(int e=s[i];e;e=next[e])
if(from[to[e]]!=from[i])d[from[i]]=1;
int ans=0;
for(int i=1;i<=w;i++)
if(!d[i])
{
if(ans){
printf("0\n");
return 0;
}else {
for(int j=1;j<=n;j++)
if(from[j]==i)ans++;
}
}
printf("%d\n",ans);
return 0;
}