poj 1182 食物链(经典种类并查集)

来源:互联网 发布:数码大师类似软件 编辑:程序博客网 时间:2024/05/27 10:43

看了大佬的博客,终于对种类并查集有了自己的理解。现写下这篇博客,加深自己对种类并查集的理解~
题目链接:http://poj.org/problem?id=1182
题目大意:都是中文没啥好说的。。。
思路:每个种类就相当于一个集团,给这个集团加个权值代表这个集团。(种类并查集也是加权并查集的一 种)。
主要是group(集团之后都用gp表示)
0 代表这个节点的和父节点的关系是同类
1代表这个节点吃他的父节点吃
2代表这个节点被他的父节点吃,也吃gp为1的节点
然后有了gp食物链就链接成功了。
然后是树的权值的更新
字丑了~
并查集三部:
建树: 每个数的跟节点赋值为本身,gp为0,未被讨论的都属于0,初始化的时候用inline可以加速
find:找到这个数的根节点(递归还是函数都是可以的),在返回前,跟新一下这个节点和父节点的关系
gp[i]=(gp[i]+gp[pa[i]])%3;//这里有个很重要的事情, 就是先压缩再更新这个我会在某个并查集中详细写一下推导!!!
unite:先进行路径压缩,更新权值 ,如果以前确定了关系,那么的话就在食物链内就可以直接验证真假关系,如果不在就并入食物链中
代码:

 #include<cstdio>const int max=50000+50; int gp[max],pa[max];inline void init(int n){    for(int i=1;i<=n;i++)    pa[i]=i,gp[i]=0;}int find(int x){    if(x==pa[x]) return x;    int fa=find(pa[x]);    gp[x]=(gp[x]+gp[pa[x]])%3;    return pa[x]=fa;}int unite(int d,int x,int y){   int fx=find(x);   int fy=find(y);   if(fx==fy){    if(d==1&&gp[x]!=gp[y]) return false;    if(d==2&&(gp[y]+1)%3!=gp[x]) return false;         return true;     }   gp[fx]=(gp[x]-gp[y]+3+d-1)%3;   pa[fx]=fy;   return true;  }int main(){    int n,m;    while(~scanf("%d%d",&n,&m))    {        init(n);        int d,x,y,sum=0;        for(int i=0;i<m;i++){            scanf("%d%d%d",&d,&x,&y);            if(x>n||y>n||(d==2&&x==y)) {                sum++; continue;            }            if(find(x)==find(y)){                if(d==2&&(gp[y]+1)%3!=gp[x]) sum++;                if(d==1&&gp[y]!=gp[x]) sum++;             } else {                if(!unite(d,x,y)) sum++;            }          }        printf("%d\n",sum);     }    return 0; }  
原创粉丝点击