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;
    }
     
     
     
     
  • 相关阅读:
    caffe常用层: batchNorm层和scale层
    简述configure、pkg-config、pkg_config_path三者的关系
    python删除list中元素的三种方法
    Leetcode 872. Leaf-Similar Trees
    Leetcode 508. Most Frequent Subtree Sum
    Leetcode 572. Subtree of Another Tree
    Leetcode 894. All Possible Full Binary Trees
    Leetcode 814. Binary Tree Pruning
    Leetcode 557. Reverse Words in a String III
    python 多维list声明时的小问题
  • 原文地址:https://www.cnblogs.com/soTired/p/4867618.html
Copyright © 2011-2022 走看看