题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶
牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果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
tarjan暴力缩点,求出度为0的强连通分量的大小。
要格外注意的是,出度为0的强连通分量只能有一个。也就是说,最后的答案是唯一一个出度为0的明星集团的大小。
证明:
①:明星奶牛被所有牛喜欢,出度只能为0。若出度不为0,明星奶牛被所有牛喜欢的同时还喜欢着某个其它奶牛,那么明星奶牛与其它奶牛之间就有一条双向边,又形成一个明星集团,与已经找出的强连通分量冲突;
②:出度为0的强连通分量只能有一个。如果不唯一,还有另一个出度为0的强连通分量,那么不符合“被其他所有牛喜欢”的条件。
因此如果找到多个明星集团,输出0。
:tarjan板子真是打一次错一次。
dfs写错时洛谷会卡一个点。。竟然就一个。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
const int maxn=100000+10;
int first[maxn],nxt[maxn],tot;
int dfn[maxn],low[maxn],scc[maxn],size[maxn],chu[maxn];
int scc_num,dfs_clock;
int n,m,ans;
stack<int>s;
struct edge
{
int f,t;
}l[maxn];
void build(int f,int t)
{
l[++tot]=(edge){f,t};
nxt[tot]=first[f];
first[f]=tot;
return;
}
void dfs(int u)
{
low[u]=dfn[u]=++dfs_clock;
s.push(u);
for(int i=first[u];i;i=nxt[i])
{
int w=l[i].t;
if(!dfn[w])
{
dfs(w);
low[u]=min(low[u],low[w]);//
}
else if(!scc[w])
{
low[u]=min(low[u],dfn[w]);//
}
}
if(low[u]==dfn[u])
{
scc_num++;
while(1)
{
int x=s.top();
s.pop();
scc[x]=scc_num;
size[scc_num]++;
if(x==u) break;
}
}
return;
}
int main()
{
int f,t;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&f,&t);
build(f,t);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i]) dfs(i);
}
for(int i=1;i<=n;i++)
{
for(int j=first[i];j;j=nxt[j])
{
int w=l[j].t;
if(scc[i]!=scc[w]) chu[scc[i]]++;
}
}
int k;
for(int i=1;i<=scc_num;i++)
{
if(chu[i]==0) ans++,k=i;
}
if(ans==1) cout<<size[k]<<'\n';
else puts("0");
return 0;
}