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;
    }
  • 相关阅读:
    前天去游泳了
    Microsoft今天开了中文的MSDN了,以后查资料有时要快了点吧
    Visual Studio .NET已检测到指定的WEB服务运行的不是ASP.NET 1.1版
    sqlserver 2005 利用游标解决标量值函数主键自增id批量导入数据问题
    nvarchar查询条件中不用加单引号''吗?
    使用标量值函数作为主键自增值的时候,动软代码生成器的插入方法需要去掉主键的参数。
    c#里的'0','1'对应sqlserver2005中的False,True
    三元运算符绑定缩略内容
    循环插入数据存储过程
    01|02|03| ====> (01,02,03)用于in id数组这种查询方式
  • 原文地址:https://www.cnblogs.com/RootVount/p/10533568.html
Copyright © 2011-2022 走看看