题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶
牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜
欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你
算出有多少头奶牛可以当明星。
输入输出格式
输入格式: 第一行:两个用空格分开的整数:N和M
第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B
输出格式: 第一行:单独一个整数,表示明星奶牛的数量
输入输出样例
输入样例#1:
3 3 1 2 2 1 2 3
输出样例#1:
1
说明
只有 3 号奶牛可以做明星
【数据范围】
10%的数据N<=20, M<=50
30%的数据N<=1000,M<=20000
70%的数据N<=5000,M<=50000
100%的数据N<=10000,M<=50000
强连通分量裸题。。。
在有向图中,如果有且仅有一个点的出度为0 (没有指向其他点的边),那么该点可以被所有点遍历到;反之,该图中没有可以被所有点遍历到的点;
在有向图中,如果一个点可以被所有点遍历到,那么这个点的出度为0
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 10010
#define MAXM 50010
using namespace std;
int n,m,c=1,d=1,top=1,s=0,ans=0;
int cstack[MAXN],head[MAXN],deep[MAXN],low[MAXN],colour[MAXN],num[MAXN],sum[MAXN];
bool beque[MAXN];
struct node{
int next,to;
}a[MAXM<<1];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline void add(int x,int y){
a[c].to=y;
a[c].next=head[x];
head[x]=c++;
}
void work(int x){
deep[x]=low[x]=d++;
beque[x]=true;
cstack[top++]=x;
for(int i=head[x];i;i=a[i].next){
int t=a[i].to;
if(!deep[t]){
work(t);
low[x]=min(low[x],low[t]);
}
else if(beque[t])
low[x]=min(low[x],deep[t]);
}
if(low[x]>=deep[x]){
s++;
do{
beque[cstack[top-1]]=false;
colour[cstack[top-1]]=s;
}while(cstack[--top]!=x);
}
}
int main(){
int x,y;
n=read();m=read();
memset(num,0,sizeof(num));
memset(sum,0,sizeof(sum));
for(int i=1;i<=m;i++){
x=read();y=read();
add(x,y);
}
for(int i=1;i<=n;i++)if(!deep[i])work(i);
for(int i=1;i<=n;i++)num[colour[i]]++;
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=a[j].next){
int t=a[j].to;
if(colour[t]!=colour[i])sum[colour[i]]++;
}
for(int i=1;i<=s;i++)
if(!sum[i]){
if(ans){ans=0;break;}
ans=i;
}
printf("%d\n",num[ans]);
return 0;
}