zoukankan      html  css  js  c++  java
  • sdnu 1078.食物链(种类并查集)

    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

    Source

     
    思路:这道题要用种类并查集,其中(x+n)代表x吃的东西,(x+2*n)代表吃x的东西
    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <string>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define ll long long
    const int inf = 0x3f3f3f3f;
    const int maxn = 1e6;
    int sign[maxn];
    int n, k;
    
    init()
    {
        for(int i = 0; i<maxn; i++)
            sign[i] = i;//使所有的点指向自己
    }
    int get(int x)
    {
        if(x == sign[x])return x;
        else
        {
            sign[x] = get(sign[x]);
            return sign[x];
        }
    }
    void unio(int x, int y)//合并x与y,师他们成为同类
    {
        int a = get(x), b = get(y);
        sign[a] = b;
    }
    int cmp1(int x, int y)//在1 x y的情况下的判断
    {
        if(x>n || y>n || x<= 0 || y <= 0)return 0;
        if(get(x+n) == get(y) || get(x+2*n) == get(y))return 0;//如果x吃的东西(x+n)与y同一个祖宗,或者吃x的东西(x+2*n)与y同一个祖宗,那就是假的
        return 1;
    }
    int cmp2(int x, int y)//在2 x y的情况下的判断(x吃y)
    {
        if(x>n || y>n || x<= 0 || y <= 0 || x == y)return 0;
        if(get(x) == get(y) || get(y) == get(x+2*n))return 0;//如果x与y为同类,或,y与吃x的东西(x+2*n)为同类,那就是假的
        return 1;
    }
    int main()
    {
        int a, b, c, sum = 0;
        scanf("%d%d", &n, &k);
        init();
        for(int i = 0; i<k; i++)
        {
            scanf("%d%d%d", &a, &b, &c);
            if(a == 1)//为1的情况
            {
                if(cmp1(b, c))//确认过眼神,它们是同类
                {
                    unio(b, c);//把b和c搞成同类
                    unio(b+n, c+n);//把b吃的东西(b+n)和c吃的东西(c+n)搞成同类
                    unio(b+2*n, c+2*n);//把吃b的东西(b+2*n)和吃c的东西(c+2*n)搞成同类
                }
                else sum++;
            }
            else
            {
                if(cmp2(b,c))//确认过眼神,它们不是同类
                {
                    unio(b, c+2*n);//把b和吃c的东西(c+2*n)搞成同类
                    unio(b+n, c);//把b吃的东西(b+n)和c搞成同类
                    unio(b+2*n, c+n);//把吃b的东西(b+2*n)和c吃的东西(c+n)搞成同类
                }
                else sum++;
            }
        }
        printf("%d
    ", sum);
        return 0;
    }
  • 相关阅读:
    mybatis基础学习3---特殊sql语句(备忘)
    5.dos网络配置命令,重新获取ip刷新dns
    Guarded Suspension设计模式
    多线程Future设计模式
    多线程不可变对象设计模式immutable
    多线程读写锁分离设计模式
    多个人过门引出线程安全问题
    库存管理系统项目总结
    简单认识C#
    数据类型,变量,与运算符
  • 原文地址:https://www.cnblogs.com/RootVount/p/10533568.html
Copyright © 2011-2022 走看看