BZOJ1051 [HAOI2006]受欢迎的牛 Tarjan 强连通缩点
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ1051
题意概括
有n只牛,有m个羡慕关系。
羡慕关系具有传递性。
如果A羡慕B,B羡慕C,那么我们认为A也羡慕C。
问有多少牛被所有其他牛羡慕。
题解
这次做这题我已经是第三遍了。
USACO经典老题啊!(奶牛)
POJ上面也有,叫popular cow。
做法:
先Tarjan强连通缩个点。
然后,统计下入度。
统计入度为0的点数。如果点数大于1,那么答案明显是0。
如果点数是1,那么答案就是唯一的入度为0的点在缩点前点的个数。
代码
#include <cstring> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cmath> using namespace std; const int N=10000+5,M=50000+5; struct Gragh{ int cnt,x[M],y[M],nxt[M],fst[N]; void set(){ cnt=0; memset(fst,0,sizeof fst); } void add(int a,int b){ x[++cnt]=a,y[cnt]=b; nxt[cnt]=fst[a],fst[a]=cnt; } }g; int n,m; int dfn[N],low[N],st[N],time,ans,top,bh[N],cnt[N]; bool inst[N],vis[N]; void Tarjan_Prepare(){ time=ans=top=0; memset(bh,0,sizeof bh); memset(st,0,sizeof st); memset(dfn,0,sizeof dfn); memset(low,0,sizeof low); memset(vis,0,sizeof vis); memset(inst,0,sizeof inst); } void Tarjan(int x){ dfn[x]=low[x]=++time; vis[x]=inst[x]=1; st[++top]=x; for (int i=g.fst[x];i;i=g.nxt[i]) if (!vis[g.y[i]]){ Tarjan(g.y[i]); low[x]=min(low[x],low[g.y[i]]); } else if (inst[g.y[i]]) low[x]=min(low[x],low[g.y[i]]); if (low[x]==dfn[x]){ ans++; bh[st[top]]=ans; inst[st[top]]=0; while (st[top--]!=x){ bh[st[top]]=ans; inst[st[top]]=0; } } } int main(){ g.set(); scanf("%d%d",&n,&m); for (int i=1,a,b;i<=m;i++){ scanf("%d%d",&a,&b); g.add(a,b); } Tarjan_Prepare(); for (int i=1;i<=n;i++) if (!vis[i]) Tarjan(i); memset(cnt,0,sizeof cnt); for (int i=1;i<=m;i++) if (bh[g.x[i]]!=bh[g.y[i]]) cnt[bh[g.x[i]]]++; int which=-1; for (int i=1;i<=ans;i++) if (cnt[i]==0){ if (which!=-1){ printf("0"); return 0; } which=i; } int Ans=0; for (int i=1;i<=n;i++) if (bh[i]==which) Ans++; printf("%d",Ans); return 0; }