• POJ 1182——食物链——————【种类并查集】


    食物链
    Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u

    Description

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 
    现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 
    有人用两种说法对这N个动物所构成的食物链关系进行描述: 
    第一种说法是"1 X Y",表示X和Y是同类。 
    第二种说法是"2 X Y",表示X吃Y。 
    此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 
    1) 当前的话与前面的某些真的话冲突,就是假话; 
    2) 当前的话中X或Y比N大,就是假话; 
    3) 当前的话表示X吃X,就是假话。 
    你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 

    Input

    第一行是两个整数N和K,以一个空格分隔。 
    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 
    若D=1,则表示X和Y是同类。 
    若D=2,则表示X吃Y。

    Output

    只有一个整数,表示假话的数目。

    Sample Input

    100 7
    1 101 1 
    2 1 2
    2 2 3 
    2 3 3 
    1 1 3 
    2 3 1 
    1 5 5
    

    Sample Output

    3


    解题思路:将关系转化成偏移量。x->y 偏移量为 0 表示同类。 x->y 偏移量为 1 表示 y 被 x 吃。 x->y 偏移量为2表示 x 被 y 吃。结点x的关系域 rela 表示父亲结点 fax 到 x的偏移量。 可以参考下面的博客学习。http://blog.csdn.net/niushuai666/article/details/6981689。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int INF = 0x3f3f3f3f;
    const int maxn = 1e5+200;
    struct Animal{
        int pa,rela;
    }anims[maxn];
    int n;
    void init(){
        for(int i = 0; i <= n; i++){
            anims[i].pa = i;        //初始化父亲域
            anims[i].rela = 0;      //初始化关系域
        }
    }
    int Find(int x){
        if(anims[x].pa == x)
            return x;
        int tmp = anims[x].pa;      //记录x原来的父亲
        anims[x].pa = Find( tmp );  //将x连到根上
        anims[x].rela = ( anims[tmp].rela  + anims[x].rela)%3;  //x与根的偏移量就是根到x原父节点的偏移量+父节点到x的偏移量
        return anims[x].pa; //返回根节点
    }
    int main(){
        int k;
        scanf("%d%d",&n,&k);
        init();
        int a,x,y;
        int cnt = 0;
        for(int i = 0;i < k; i++){
            scanf("%d%d%d",&a,&x,&y);
            if(x>n||y>n){
                cnt++;
            }else if( a == 2&& x == y){
                cnt++;
            }else {
                int rootx = Find(x);    //x的根
                int rooty = Find(y);    //y的根
                if(rootx == rooty){     //如果根相同,说明在一个集合中,有一定关系
                    //如果根到x、y的偏移量相同,说明x、y同类
                    if(a == 1&& anims[x].rela != anims[y].rela){
                        cnt++;
                    }else if(a == 2){
                        // x到y的偏移量等于x到根的偏移量加上根到y的偏移量
                        if( a - 1 != (3 + anims[y].rela - anims[x].rela)%3 ){
                            cnt++;
                        }
                    }
                }else{  //合并
                    //让x的根作为rooty集合的根
                    anims[rooty].pa = rootx;
                    //x的根rootx到rooty的偏移量为rootx到x的偏移量(anims[x].rela) + x到y的偏移量(a-1) + y到rooty的偏移量(-anims[y].rela)
                    anims[rooty].rela = (3 + anims[x].rela + a-1 - anims[y].rela )%3;
                }
            }
        }
        printf("%d
    ",cnt);
        return 0;
    }
    

      



  • 相关阅读:
    CDH 6.0.1 集群搭建 「Process」
    CDH 6.0.1 集群搭建 「Before install」
    利用 Docker 搭建单机的 Cloudera CDH 以及使用实践
    vue2.x学习笔记(十七)
    vue2.x学习笔记(十六)
    vue2.x学习笔记(十五)
    vue2.x学习笔记(十四)
    vue2.x学习笔记(十三)
    vue2.x学习笔记(十二)
    vue2.x学习笔记(十一)
  • 原文地址:https://www.cnblogs.com/chengsheng/p/4906600.html
Copyright © 2020-2023  润新知