Bzoj1051 受欢迎的牛
每一头牛的愿望就是变成一头最受欢迎的牛。现在有 N 头牛,给你 M 对整数 (A,B),表示牛 A 认为牛 B 受欢迎。这种关系是具有传递性的,如果 A 认为 B 受欢迎,B 认为 C 受欢迎,那么牛 A 也认为牛 C 受欢迎。你的任务是求出有多少头牛被除自己之外的所有牛认为是受欢迎的
第一眼是个很弱智的Tarjan缩点,然后判断有没有连通分量的入度为连通分量个数减一
但是我把传递性想的太简单了
如果有下图这样的,我就只会判定出3号点有一个入度,但是正确值为2
所以我们换一个角度,从缩点的性质来考虑
我们知道,缩点之后的图是一个DAG(有向无环图)
所以一个节点如果有出度,就不可能被它所到的点崇拜,否则就有环了
所以我们得出了第一条结论,只有出度为零的点才能被所有点崇拜
然后有的人会问如果有多个节点的出度为零怎么办呢
即使不从图的角度来看,这两个出度为零的点也是不可能互相崇拜的,所以不成立
下面给出代码:
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<string> #include<cmath> using namespace std; inline int rd(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); return ; } int n,m; int head[1000006],nxt[1000006],to[1000006]; int total; void add(int x,int y){ total++; to[total]=y; nxt[total]=head[x]; head[x]=total; return ; } int dfn[1000006]; int low[1000006]; int tot=0; int book[1000006]; int sta[1000006]; int set=0; int v[1000006]; int cnt=0; int color[1000006]; void tarjan(int x){ low[x]=dfn[x]=++tot; sta[++set]=x; book[x]=1; for(int e=head[x];e;e=nxt[e]){ if(!dfn[to[e]]){ tarjan(to[e]); low[x]=min(low[x],low[to[e]]); } else if(book[to[e]]) low[x]=min(low[x],dfn[to[e]]); } if(dfn[x]==low[x]){ cnt++; book[x]=0; v[cnt]++; color[x]=cnt; while(set&&sta[set]!=x){ book[sta[set]]=0; v[cnt]++; color[sta[set]]=cnt; set--; } set--; } return ; } int du[1000006]; int main(){ n=rd(),m=rd(); for(int i=1;i<=m;i++){ int x=rd(),y=rd(); add(x,y); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); int ans=0; for(int i=1;i<=n;i++){ for(int e=head[i];e;e=nxt[e]){ if(color[i]!=color[to[e]]){ du[color[i]]++; } } } int num=0; for(int i=1;i<=cnt;i++){ if(du[i]==0){ num++; ans+=v[i]; } } if(num==1) write(ans); else write(0); return 0; }
蒟蒻总是更懂你✿✿ヽ(°▽°)ノ✿