zoukankan      html  css  js  c++  java
  • Poj1182--食物链(种类并查集)

    食物链
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 54779   Accepted: 16061

    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

     
    解这个题的方法很巧妙, 看了两种不同题解, 有一种不理解公式是怎么推出来的 ,据说是利用向量。 So--- 用了种比较巧的方法。
    题解(参考别人): 
        别人好像是参考的《挑战程序设计竞赛》88页。
        对于每只动物创建三个元素 i --> a; i --> b; i --> c; 用3*n 个元素建立并查集, 此并查集维护信息如下:
          <1>: i --> x: 该动物属于哪个种群;
                  <2>: 并查集中两个元素同时发生或同时不发生。
        可以把<0, n>,  <n, n+n>, <n+n, n+n+n> 分别看作A, B, C三个种群。
          ①如果两只动物属于同一种群, 可以在集合中加入边 <a, b>, <a+n, b+n>, <a+2*n,  b+2*n>;
          ②如果两只动物是捕食关系, 可以按照题目中信息在集合中+边 <a, b+n>; <a+n, b+2*n>; <a+2*n, b>;
        题目中求的是假话的数量(重要信息都在题目中)。 
          这部分细心, 有点像模拟。
    写了这么多, 感觉自己有点"虚", 碰到它, 不看题解, 估计也解不出来。
     
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define N 50001
    using namespace std;
    int father[N*3];
    void Init(int n)
    {
        for(int i = 1; i <= n; i++)
            father[i] = i;
    }
    int Find(int a)
    {
        if(a == father[a])
            return a;
        else
            return father[a] = Find(father[a]); 
    }
    void Mercy(int a, int b)
    {
        int Q = Find(a);
        int P = Find(b);
        if(Q != P)
            father[Q] = P;
    } 
    void Solve(int n, int m)
    {
        int totAl = 0;
        for(int i = 1; i <= m; i++)
        {
            int T, x, y;
            scanf("%d%d%d", &T, &x, &y);
            if(x <= 0 || y <= 0 || x > n || y > n)
            {
                totAl++;
                continue;
            }
            if(T == 1)
            {
                if(Find(x) == Find(y + n) || Find(x) == Find(y + 2*n))
                    totAl++;
                else
                {
                    Mercy(x, y);
                    Mercy(x+n, y+n);
                    Mercy(x+2*n, y+2*n);
                }
            }
            if(T == 2)
            {
                if(Find(x) == Find(y) || Find(x) == Find(y+2*n))
                    totAl++;
                else
                {
                    Mercy(x, y+n);
                    Mercy(x+n, y+2*n);
                    Mercy(x+2*n, y);
                } 
            }
        }
        printf("%d
    ", totAl);
    }
    int main()
    {
        int n, m;
        scanf("%d%d", &n, &m);
        Init(n*3); 
        Solve(n, m);
        return 0;
    }
     
     
     
     
  • 相关阅读:
    Java实现 LeetCode 394 字符串解码
    Java实现 LeetCode 394 字符串解码
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 390 消除游戏
    Java实现 LeetCode 390 消除游戏
  • 原文地址:https://www.cnblogs.com/soTired/p/4867618.html
Copyright © 2011-2022 走看看