题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你算出有多少头奶牛可以当明星。
输入输出格式
输入格式:
第一行:两个用空格分开的整数:N和M
第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B
输出格式:
第一行:单独一个整数,表示明星奶牛的数量
输入输出样例
输入样例
3 3
1 2
2 1
2 3
输出样例
1
说明
只有 3 号奶牛可以做明星
【数据范围】
10%的数据N<=20, M<=50
30%的数据N<=1000,M<=20000
70%的数据N<=5000,M<=50000
100%的数据N<=10000,M<=50000
一个比较裸的scc,求一个scc,然后缩点,数一下每个scc的出度,有且仅有一个scc的出度为0时是符合条件的,输出scc的大小,否则输出0.
代码如下
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int size = 200010;
stack < int > s;
int l[size],head[size],next[size];
int tot = 1;
void build(int f,int t)
{
l[tot] = t;
next[tot] = head[f];
head[f] = tot ++;
}
int n,m;
int dfs_clock,low[size],dfn[size],scc[size],scc_num;
int tarjan(int u)
{
dfn[u] = low[u] = ++ dfs_clock;
s.push(u);
for(int i = head[u] ; i ; i = next[i])
{
int v = l[i];
if(!dfn[v])
{
low[v] = tarjan(v);
low[u] = min(low[v],low[u]);
}
else if(!scc[v])
low[u] = min(low[u],dfn[v]);
}
if(dfn[u] == low[u])
{
scc_num ++;
while(12 < 450)
{
if(s.empty())
break;
int v = s.top();
s.pop();
scc[v] = scc_num;
if(v == u)
break;
}
}
return low[u];
}
int c[size];
void init()
{
memset(head,0,sizeof(head));
memset(next,0,sizeof(next));
memset(l,0,sizeof(l));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(scc,0,sizeof(scc));
while(!s.empty())
s.pop();
tot = 1;
dfs_clock = 0;
scc_num = 0;
}
int main()
{
// while(scanf("%d%d",&n,&m) != EOF)
// {
scanf("%d%d",&n,&m);
init();
for(int i = 1 ; i <= m ; i ++)
{
int f,t;
scanf("%d%d",&f,&t);
build(f,t);
}
for(int i = 1 ; i <= n ; i ++)
if(!dfn[i])
tarjan(i);
int newm = 0;
int pos = 0;
for(int i = 1 ; i <= n ; i ++)
{
for(int j = head[i] ; j ; j = next[j])
{
int t = l[j];
if(scc[i] != scc[t])
c[scc[i]] ++;
}
}
int ans = 0;
for(int i = 1 ; i <= scc_num ; i ++)
if(c[i] == 0)
{
pos = i;
newm ++;
}
if(newm == 1)
{
for(int i = 1 ; i <= n ; i ++)
if(scc[i] == pos)
ans ++;
printf("%d\n",ans);
}
else
puts("0");
// }
return 0;
}