zoukankan      html  css  js  c++  java
  • POJ 1182[并查集]

    动物王国中有三类动物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在同一集合中,那么x和y都在A,x和y都在B,x和y都在C;

    第二种状态 x吃y,那么x在A,y在B,或者x在B,y在C,或者x在C,y在A;

    每种状态都标记出来,如果出现矛盾,那么就ans加一。

    比如说,本次说x和y在同一阵营,但是查询发现,x已经吃了y,或者y吃了x,那么当然就不行。

    还有就是并查集还是写成函数的好,这样代码清爽。不然只写一个find(int x),(绝对不止我一个人这么做),代码会很难看,逻辑或许看上去不是那么清楚。

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    using namespace std;
    const int N = 50000 + 5;
    int fa[3 * N];
    int n, k, x, y;
    
    int init(int n)
    {
        for(int i = 0; i <= n; i++)
            fa[i] = i;
    }
    int find(int x)
    {
        return x == fa[x] ? x : fa[x] = find(fa[x]);
    }
    void unite(int x, int y)
    {
        int xx = find(x);
        int yy = find(y);
        if(xx != yy)
        {
            fa[xx] = yy;
        }
    }
    bool same(int x, int y)
    {
        return find(x) == find(y);
    }
    
    void solve()
    {
        scanf("%d%d", &n, &k);
        init(3*n);
        int ans = 0;
        while(k--)
        {
            int op;
            scanf("%d%d%d", &op, &x, &y);
            x--; y--;
            if(x < 0 || x >= n || y < 0 || y >= n)
            {
                ans++;
                continue;
            }
            if(op == 1)
            {
                if(same(x, y + n) || same(x, y + 2 * n))
                {
                    ans++;
                }
                else
                {
                    unite(x, y);
                    unite(x + n, y + n);
                    unite(x + 2 * n, y + 2 * n);
                }
            }
            else
            {
                if(same(x, y) || same(x, y + 2 * n))
                {
                    ans++;
                }
                else
                {
                    unite(x, y + n);
                    unite(x + n, y + 2 * n);
                    unite(x + 2 * n, y);
                }
            }
        }
        printf("%d
    ", ans);
    }
    
    int main()
    {
        solve();
        return 0;
    }
    如果有错误,请指出,谢谢
  • 相关阅读:
    OpenCV on Mac OSX: A step-by-step guide
    opencv打开摄像头获取视频程序
    使用find_if算法搜寻map的value
    c++如何理解map对象的value_type是pair类型
    关联容器执行器指定排序规则
    仿函数和函数配接器
    C++的异常处理
    back_insert_iterator和insert_iterator
    copy函数与ostream_iterator、reverse_iterator
    const_cast
  • 原文地址:https://www.cnblogs.com/Alruddy/p/7197374.html
Copyright © 2011-2022 走看看