题目链接https://www.luogu.org/problem/show?pid=2341
题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶
牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果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
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#define N 50005*2
#include <set>
using namespace std;
int n,m;
int dfn[N];
int tim=0;
int topp=0;
int low[N];
int bel[N];
int cnt;
bool v[N];
int stack[N];
int out[N];
int in[N];
int size[N];
vector <int> g[N];
vector <int> outt[N];
set <int> to[N];
void tarjan(int x){
dfn[x]=low[x]=++tim;
stack[++topp]=x;
v[x]=true;
for(int i=0;i<g[x].size();i++){
if(!dfn[g[x][i]]){
tarjan(g[x][i]);
low[x]=min(low[x],low[g[x][i]]);
}
else if(v[g[x][i]]) low[x]=min(low[x],dfn[g[x][i]]);
}
if(low[x]==dfn[x]){
int vv;
cnt++;
do{
vv=stack[topp--];
bel[vv]=cnt;
size[cnt]++;
v[vv]=false;
}while(vv!=x);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
g[a].push_back(b);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) tarjan(i);
}
for(int i=1;i<=n;i++)
for(int j=0;j<g[i].size();j++){
int dng=g[i][j];
if(bel[i]!=bel[dng])
{
to[bel[i]].insert(bel[j]);//防重边
}
}
int ans=0;
int pos;
for(int i=1;i<=cnt;i++)
if(to[i].empty())
ans++, pos=i;
if(ans==1) printf("%d",size[pos]);
else printf("0");
return 0;
}
tarjan缩点