poj1182->食物连->并查集

poj1182 食物链

思路来源,但是有所不同,详细异同点代码中有注释。

并查集小结并查集算法主要是根据元素之间的关系去快速查询(Query ),我们在将元素加入(Merge )我们的并查集中时要实时的更新关系函数(Relation 数组),弄清楚谁是谁的父节点(GetPar),谁是谁们的根节点(Parent 数组)

#include<cstdio>

using namespace std;

const int Max_num = 50005;
int n,k;
int Parent[Max_num];
int Relation[Max_num];

void Init(){
    for(int i= 0;i<=n;i++){
        Parent[i] = i;
        //Relation[i] = 0 ->本身 1-> 吃掉父节点2->  被父节点吃掉
        Relation[i] = 0;
        }
}

int GetPar(int x){
    if(Parent[x] == x) return x;
    int pa = Parent[x];
    Parent[x] = GetPar(Parent[x]);
    //更新关系函数
    Relation[x] = (Relation[x]+Relation[pa])%3;
    return Parent[x];
}

bool Query(int x,int y,int d){
    int a = GetPar(x);
    int b = GetPar(y);
    if(a ==b){
        if(d == 1 && Relation[x] != Relation[y]) return false;
        if(d == 2){
            if(Relation[x] == 1 && Relation[y] != 0) return false;
            if(Relation[x] == 2 && Relation[y] != 1) return false;
            if(Relation[x] == 0 && Relation[y] != 2) return false;
        }
        return true;
    }
    /* 更新关系函数
    x->y 代表y是父节点
    0 :没关系
    1 :吃掉y
    2 :被y吃掉

    用向量的进行巧解
    */
    //x吃掉y =》 b为a的父节点
    Parent[a] = b;
    if(d == 2){
    //有减法所以加三
        Relation[a] = (Relation[y]+1-Relation[x] +3)%3;
    }else{
        Relation[a] =(Relation[y]-Relation[x]+3)%3;
    }
    return true;
}


int main(){
    int x,y,d;
    scanf("%d%d",&n,&k);
    Init();
    int ans = 0;
    for(int i = 0;i<k;i++){
        scanf("%d%d%d",&d,&x,&y);
        if(x>n || y>n || (d==2 && x == y)){
            ans++;
            //continue忘了就是二倍
            continue;
        }
        if(!Query( x,y,d)){
            ans++;
        }
    }
    printf("%d\n",ans);
    return 0;
}


你可能感兴趣的:(poj1182->食物连->并查集)