Description:
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶
牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜
欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你
算出有多少头奶牛可以当明星。
Analysis:
显然强连通分量里的点都互相喜欢,跑tarjan求强连通分量,统计每个强连通分量的出度,如果有一个强连通分量出度为0,则输出该强连通分量的大小。若同时存在多个强连通分量出度为0,则不满足题意,输出0。
Code:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<stack>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 10001;
const int maxm = 50005;
int s[maxn],top;
//stack<int> s;
struct edge{
int next,to;
}e[maxm];
// dfn[] := dfs序,low[] := 该点及其子树所能追溯的的最小的dfn值
// scc[] := 属于哪个强连通分量,Scc[] := 强连通分量的大小
// in[] := 强连通分量的入度,out[] := 强连通分量的出度
int head[maxn],dfn[maxn],low[maxn],scc[maxn],Scc[maxn],in[maxn],out[maxn],num_dfs,num_scc,num_edge,n,m,cnt,ans;
void tarjan(int u){
dfn[u] = low[u] = ++num_dfs;
s[++top] = u;
//s.push(u);
for(int i = head[u];i;i = e[i].next){
int v = e[i].to;
if(!dfn[v]){
//如果v未访问,则继续递归
tarjan(v);
low[u] = min(low[u],low[v]);
}else{
if(!scc[v])
low[u] = min(low[u],dfn[v]);
}
}
if(low[u] == dfn[u]){
++num_scc;
Scc[num_scc]++;
scc[u] = num_scc;
while(s[top] != u){
Scc[num_scc]++;
scc[s[top]] = num_scc;//同一个强连通分量的点放在栈中
--top;
}
--top;
}
}
void add(int from,int to){
e[++num_edge].next = head[from];
e[num_edge].to = to;
head[from] = num_edge;
}
int main(){
scanf("%d %d",&n,&m);
for(int i = 1;i <= m;i++){
int a,b;
scanf("%d %d",&a,&b);
add(a,b);
}
//tarjan找强连通分量
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=e[j].next){
int t = e[j].to;
//枚举原图中的两个相连的点,若不属于同一个强连通分量,则其入度、出度分别+1
if(scc[i] != scc[t])
in[scc[t]]++,out[scc[i]]++;
}
}
//if(scc[i]!=scc[t]) outd[belong[i]]++,ind[belong[t]]++;
ans = 0;
for(int i = 1;i <= num_scc;i++){
if(!out[i]){
if(ans){
//如果存在多个出度为0的强连通分量,则无解
ans = 0;
break;
}
else{
ans = Scc[i];
}
}
}
printf("%d",ans);
return 0;
}