BZOJ 1051 受欢迎的牛

来源:互联网 发布:大连淘宝代运营 编辑:程序博客网 时间:2024/06/07 02:07

今日莫名连续一遍A题
过于开心
就再写一篇博客吧

1051: [HAOI2006]受欢迎的牛
  每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这
种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头
牛被所有的牛认为是受欢迎的。
Input
  第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可
能出现多个A,B)
Output
  一个数,即有多少头牛被所有的牛认为是受欢迎的。
Sample Input
3 3
1 2
2 1
2 3
Sample Output
1

100%的数据N<=10000,M<=50000

嗯,也不知道为啥,一看这道题就对着frf瞎扯:“我咋觉得这道题tarjan”
结果发现frf就拿着tarjan开始搞了
后来一想发现,诶?这么神奇?好像真的是tarjan。。

首先
我们发现这道题一个性质,对于一个环里所有牛的受欢迎情况是完全一样的
所以就可以用tarjan 缩点,把一张图弄成一个无环图处理
所以一头又一头牛我们就把他们缩成了一坨又一坨牛

于是我思谋着,重新建图好麻烦啊,偷个懒试试并查集?
结果在纸上刚画出两个圈圈,发现,诶?这么神奇?好像真的是并查集

接下来
我们又发现一个性质,如果我们每次合并并查集都按照边的方向合并的话
就是如果y受x欢迎,那么我们让fa[father(x)]=father(y)
那么如果某一坨牛是受到每坨牛欢迎的话,那么他的fa一定是自己
【细细一想之后再继续】
………..
这时候frf特别聪明,一语道破问题所在:“那如果这张图本身就不连通呢?”
结果坚持偷懒的我一不小心发现,我们可以记录fa是自己的点的个数
如果个数不是1,那么答案一定是0

嗯…..补充一下无环以后这张图有这么一个神奇的性质
要么有且只有一坨牛受其他所有坨牛欢迎
要么就没有(这个我画了三个圈圈和三个箭头看出来的23333)

所以我们就很容易的知道答案就是最后得出的那坨牛含有的牛的数量
或者是0

最后,代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;#if 0Writer: Goes && G.S.M.Just a gameEnjoy it#endifinline int read(){    char ch='*';    while(!isdigit(ch=getchar()));    int num=ch-'0';    while(isdigit(ch=getchar()))num=num*10+ch-'0';    return num;}const int N=10005;const int M=50005;int n,m;struct ss{    int to,nex,s;}edge[M];int head[N],ecnt;void add(int y,int x){    edge[++ecnt]=(ss){y,head[x],x};    head[x]=ecnt;}int zz[N],tot,num[N];bool vis[N];int dfn[N],low[N],tim,stack[N],top;void tarjan(int pos){    dfn[pos]=low[pos]=++tim;    stack[++top]=pos;vis[pos]=true;    for(int i=head[pos],v=edge[i].to;i;i=edge[i].nex,v=edge[i].to)    if(!dfn[v])      tarjan(v),low[pos]=min(low[pos],low[v]);    else if(vis[v])  low[pos]=min(low[pos],dfn[v]);    if(low[pos]==dfn[pos]){        ++tot;vis[pos]=false;        while(stack[top+1]!=pos){            zz[stack[top]]=tot;            vis[stack[top]]=false;            top--;num[tot]++;        }    }}int fa[N];inline int find_father(int x){    if(fa[x]!=x) return fa[x]=find_father(fa[x]);    else return fa[x];}void new_add(int x,int y){    int fx=find_father(x),fy=find_father(y);    if(fx==fy) return ;        fa[fx]=fy;}int main(){    n=read(),m=read();    for(int i=1;i<=m;i++)        add(read(),read());    for(int i=1;i<=n;i++)    if(!dfn[i]) tarjan(i);    //new build    for(int i=1;i<=tot;i++) fa[i]=i;    for(int i=1;i<=m;i++)        new_add(zz[edge[i].s],zz[edge[i].to]);    int sum=0,ans;    for(int i=1;i<=tot;i++)    if(fa[i]==i) sum++,ans=num[i];    if(sum!=1) printf("%d",0);    else printf("%d",ans);    return 0;    //一开始tarjan 写挂了,所以check了一下    cout<<tot<<endl;    for(int i=1;i<=n;i++)        cout<<zz[i]<<" ";}
原创粉丝点击