POJ 1182 食物链 分类并查集

点击打开链接

思路通过

通过将根分成3部分

应该也是属于分组并查集(种类并查集)。
对于这道题目,我们可以这样来理解,
建立3个集合A,B,C,
集合A表示和a是同一种类的元素,
集合B表示的是与 “a吃的元素” 是同一种类的元素,
集合C表示的是与 “吃a的元素” 是同一种类的元素。详细解释附在代码中。

三个集合{元素|1~3*n}其中对于任意一个集合,集合中元素(1~n)吃(n+1~2*n),(n+1~2*n)吃(2*n+1~3*n),(2*n+1~3*n)吃(1~n).
对于x和y 是同类.并且x和y不再一个结合的情况下,判断(y+n)、(y+2n)是否和x在一个集合,若都不是,那么(x,y)并成一个集合.(x+n,y+n)并成一个集合.(x+2*n,y+2*n)并成一个集合.
对于x 吃 y.如果x 和 (y+n)不再一个结合的情况下,判断 y、(y+2*n) 是否和 x 是在一个集合,若都不是,那么(x,y+n)并成一个集合.(x+n,y+2*n)并成一个集合.(x+2*n,y)并成一个集合.
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#define LL long long
using namespace std;
int bin[160000];
int Find(int x)
{
    return x==bin[x]?x:bin[x]=Find(bin[x]);
}
void Union(int x,int y)
{
    int fx=Find(x);
    int fy=Find(y);
    if(fx!=fy)
        bin[fx]=fy;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1; i<=3*n; i++)
        bin[i]=i;
    int num=0;
    for(int i=0; i<m; i++)
    {
        int d,x,y;
        scanf("%d%d%d",&d,&x,&y);
        if(x>n||y>n||x<1||y<1)
        {
            num++;
            continue;
        }
        if(d==1)
        {      ///x吃y的关系              y吃x
            if(Find(x)==Find(y+n)||Find(x)==Find(y+2*n))
                num++;
            else
            {   ///建立同类的关系
                Union(x,y);
                Union(x+n,y+n);
                Union(x+2*n,y+2*n);
            }
        }
        else
        {
            ///同类              y吃x
            if(Find(x)==Find(y)||Find(x)==Find(y+2*n))
                num++;
            else
            {  ///建立x吃y的关系
                Union(x,y+n);
                Union(x+n,y+2*n);
                Union(x+2*n,y);
            }
        }
    }
    printf("%d\n",num);
    return 0;
}


你可能感兴趣的:(POJ 1182 食物链 分类并查集)