【bzoj1051】【HAOI2006】受欢迎的牛
题目描述
每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你算出有多少头奶牛可以当明星。
输入
第一行:两个用空格分开的整数:N和M
第二行到第M + 1行:每行两个用空格分开的整数:A和B,表示A喜欢B
输出
第一行:单独一个整数,表示明星奶牛的数量
样例输入
3 3 1 2 2 1 2 3
样例输出
1
题解
tarjan缩点模版。
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn=10000+50; const int maxm=50000+50; int fir[maxn],to[maxm],nex[maxm],ecnt,deep,sum; int n,m,x,y,col[maxn],du[maxn],cnt[maxn],stack[maxn],low[maxn],dfn[maxn],t,tmp; bool vis[maxn]; void add_edge(int u,int v){ nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v; } template<typename T>void read(T& aa){ char cc; ll ff;aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int tarjan(int u){ dfn[u]=++deep; low[u]=deep; vis[u]=1; stack[++t]=u; for(int e=fir[u];e;e=nex[e]){ int v=to[e]; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else{ if(vis[v]) low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ col[u]=++sum; vis[u]=0; while(stack[t]!=u){ col[stack[t]]=sum; vis[stack[t--]]=0; } t--; } } int main(){ read(n),read(m); for(int i=1;i<=m;i++){ read(x),read(y); add_edge(x,y); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++){ for(int e=fir[i];e;e=nex[e]){ int v=to[e]; if(col[i]!=col[v]) du[col[i]]++; } cnt[col[i]]++; } for(int i=1;i<=sum;i++) if(du[i]==0){ tmp++;x=i; } if(tmp==0) cout<<0<<endl; else if(tmp>1) cout<<0<<endl; else cout<<cnt[x]<<endl; return 0; }