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;
    }
     
     
     
     
  • 相关阅读:
    理解MVC MVVM MVP设计模式
    跨域问题详解
    JWT认证
    Django缓存
    API文档自动生成
    DRF分页器
    DRF请求和响应,以及Response对象重新封装
    drf认证、权限、频率、过滤、排序、异常处理
    drf之视图组件以及自动化路由
    【python面向对象实战练习】植物大战僵尸
  • 原文地址:https://www.cnblogs.com/soTired/p/4867618.html
Copyright © 2011-2022 走看看