题面
【题目描述】
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
【输入】
第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)
【输出】
一个数,即有多少头牛被所有的牛认为是受欢迎的。
【样例输入】
3 3
1 2
2 1
2 3
【样例输出】
1
【数据范围】
100%的数据N<=10000,M<=50000
算法分析
强连通分量缩点。
在同一个强连通分量里,牛肯定是互相受欢迎的,因此需要考虑强连通分量之外的点。对所有强连通分量进行缩点,形成了一个有向无环图。
如存在以下关系:
进行缩点知之后,如下:
通过观察可以发现,如果一个点
S
S
S(这里的点指缩点后的强联通分量)被其他点受欢迎,那么这个点的出度
=
=
=
0
0
0,这样才能保证其他点直接指向或者间接指向点
S
S
S,同时这个点不能指向其他点,且只能有一个出度为
0
0
0的。(大家可以画几个图验证一下)
最后的答案就是缩点后,出度为
0
0
0,且只有一个出度为0的强连通分量包含的结点数目。
需要注意,进行缩点前的边
i
i
i——>
j
j
j,缩点后,边就为
s
s
c
[
i
]
ssc[i]
ssc[i]——>
s
s
c
[
j
]
ssc[j]
ssc[j],
s
s
c
[
i
]
ssc[i]
ssc[i]表示第
i
i
i个点属于第
s
s
c
[
i
]
ssc[i]
ssc[i]个强连通分量。
参考程序
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
int n,m,timee,low[10010],dfn[10010],h[10010];
int scc[10010],zh,du[10010];
int fist[100010],to[100010],nex[100010],t;//链表存图
int s[10010],top,now[10010];//栈
void add(int x,int y)
{
to[++t]=y;
nex[t]=fist[x];
fist[x]=t;
return;
}
int read(){ //快读
int k=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
return k;
}
void tarjin(int u)
{
low[u]=dfn[u]=++timee;
s[++top]=u;
now[u]=1;
h[u]=1;
int v;
for(int i=fist[u];i!=-1;i=nex[i])
{
v=to[i];
if(h[v]==0)
{
tarjin(v);
low[u]=min(low[u],low[v]);
}
else if(now[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
zh++;
do
{
v=s[top];
top--;
scc[v]=zh;//缩点
now[v]=0;
}while(u!=v&&top>0);
}
return ;
}
int main()
{
n=read();m=read();
int x,y;
memset(fist,-1,sizeof(fist));
for(int i=1;i<=m;i++)
{
x=read();y=read();
add(x,y);
}
for(int i=1;i<=n;i++)
if(h[i]==0) tarjin(i);
for(int i=1;i<=n;i++)
{
for(int j=fist[i];j!=-1;j=nex[j])
{
if(scc[i]!=scc[to[j]]) du[scc[i]]++;//求强联通分量的出度
}
}
int sum=0,ans;
for(int i=1;i<=zh;i++)
{
if(!du[i]) {sum++;ans=i;}
}
if(sum==1) //出度为0且只有一个有解
{
sum=0;
for(int i=1;i<=n;i++)
{
if(scc[i]==ans) sum++; //在出度为0的强连通分量里的所有结点都满足情况
}
printf("%d\n",sum);
}
else
printf("0");
return 0;
}