POJ 1182 食物链 (另一种简单易懂的方法)

网上大多数题解都是用的带权并查集方法,这个方法就不详细说了。

这里介绍另一种方法,个人觉得理解起来更容易。

首先,考虑如何保存动物之间的关系,自然想到用数组 eat[i] = j 来表示 i 吃 j 的关系,用并查集来保存已经确定是同类的动物。

但光是这样远远不够,我们还需要用三角环形来表示动物之间的关系。

******************

1


2      3

******************

这个三角形就表示 1 吃 3  ,3 吃 2 , 2 吃 1。

******************

4


5      6

******************

这个三角形表示 4 吃 6  ,6 吃 5 , 5 吃 4。

如果来了新关系 1 和 4 是同类 ,我们只需要把两个三角形合并成一个三角形:

******************

1,4


2,5 3,6

******************

这时候只需要用并查集把同类动物保存起来就行了,派每个并查集的祖宗放在三角形里。

但是一开始是没有三角形的,为了代码简单一点可以人为初始化生成三角形:

****************************

i


i+100000       i+50000

****************************

这样的话一开始就全是三角形,写代码只需要写三角形合并代码就行了。

思想大致就是这样,其他细节自行思考。

#include<cstdio>
#include<algorithm>
using namespace std;
int fa[50005*3],eat[50005*3];
int f(int x){
    if(fa[x]!=x)
        fa[x] = f(fa[x]);
    return fa[x];
}
void link(int a,int b){ //三角形合并,a和b是同类
    int tfa1=f(a),tfa2=f(b),Eat,n1,n2;
    for(int i=0;i<3;i++) {
        Eat = min(eat[tfa1],eat[tfa2]);
        n1 = f(eat[tfa1]);
        n2 = f(eat[tfa2]);
        if(tfa2<tfa1) fa[tfa1] = tfa2;
        else fa[tfa2] = tfa1;
        eat[tfa2] = eat[tfa1] =  Eat;
        tfa1 = n1;tfa2 = n2;
    }
    return;
}
int main(){
    int n,k,d,a,b,t,ta,tb,ans;
    scanf("%d%d",&n,&k);
    ans = 0;
    for(int i=1;i<=100000;i++) {
        eat[i]=i+50000;
        fa[i] = i;
    }
    for(int i=100001;i<=150000;i++) {
        eat[i]=i-100000;
        fa[i] = i;
    }
    for(int i=0;i<k;i++){
        scanf("%d%d%d",&d,&a,&b);
        if(a>n||b>n) ans++;
        else if(d==1)
            if(f(eat[f(a)])==f(b)||f(eat[f(b)])==f(a)) ans++;
            else link(a,b);
        else if(d==2)
            if(f(a)==f(b)||f(eat[f(b)])==f(a)) ans++;
            else link(eat[f(a)],b);
    }
    printf("%d\n",ans);
    return 0;
}




你可能感兴趣的:(并查集)