题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果 AA 喜欢 BB,BB 喜欢 CC,那么 AA 也喜欢 CC。牛栏里共有 NN 头奶牛,给定一些奶牛之间的爱慕关系,请你算出有多少头奶牛可以当明星。
输入格式
第一行:两个用空格分开的整数:NN 和 MM。
接下来 MM 行:每行两个用空格分开的整数:AA 和 BB,表示 AA 喜欢 BB。
输出格式
一行单独一个整数,表示明星奶牛的数量。
题解:
Tarjan缩点,然后判断是否有且仅有一个点的出度为0,因为如果有两个或以上的点出度为0,这些奶牛是不可能相互喜欢的,那么答案就是唯一的出度为0的那个点包含的强连通分量的点的个数
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define LL long long
const int MAXN = 1e4+50;
const int MAXM = 5e4+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
int dfn[MAXN],low[MAXN],num[MAXN],bel[MAXN],instack[MAXN],st[MAXN];
int n,m,k,tot,cnt,top,out[MAXN];
int head[MAXN],to[MAXM],nxt[MAXM];
inline void add(int u,int v){ to[++tot]=v; nxt[tot]=head[u]; head[u]=tot; }
void tarjan(int u){
dfn[u]=low[u]=++cnt; st[++top]=u; instack[u]=1;
for(int i=head[u];i;i=nxt[i]){
if(!dfn[to[i]]) tarjan(to[i]),low[u]=min(low[u],low[to[i]]);
else if(instack[to[i]]) low[u]=min(low[u],dfn[to[i]]);
}
if(dfn[u]==low[u]){
++k; int v;
do{
v=st[top--]; instack[v]=0; bel[v]=k; num[k]++;
}while(u!=v);
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
#endif // ONLINE_JUDGE
scanf("%d%d",&n,&m); int res=0;
for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),add(u,v);
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=nxt[j])
if(bel[i]!=bel[to[j]])
out[bel[i]]++;
for(int i=1;i<=k;i++){
if(!out[i]){
if(res){ puts("0");return 0; }
res = i;
}
}
printf("%d\n",num[res]);
return 0;
}