zoukankan      html  css  js  c++  java
  • POJ1182 食物链

    食物链

    总时间限制: 
    1000ms
     
    内存限制: 
    65536kB
    描述
    动物王国中有三类动物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),输出假话的总数。
    输入
    第一行是两个整数N和K,以一个空格分隔。
    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
    若D=1,则表示X和Y是同类。
    若D=2,则表示X吃Y。
    输出
    只有一个整数,表示假话的数目。

    【题解】

    运用并查集,并在压缩路径与合并两种操作中维护了必要信息:根节点与节点i的关系R[i],方向为由根节点指向该节点。并且:

    R[x]==0,x与根节点同类;R[x]==1,x吃根节点;R[x]==2,x被根节点吃

    由穷举法可知R[i]满足向量的加法性质:设r为节点x1与节点x2的关系,则 r = (3 - R[x1] + R[x2]) % 3。其中,3 - R[x1]为x1到根节点的关系,R[x2]为根节点到节点i的关系。

    【代码】

     1 #include <iostream>
     2 using namespace std;
     3                                   //parent[i]:i的根节点
     4 int parent[50005], R[50005] = {}; //R[x]==0,同类;R[x]==1,x吃根节点;R[x]==2,x被根节点吃
     5                 
     6 int GetRoot(int &x)
     7 {
     8     if (parent[x] == x)
     9         return parent[x];
    10     int tmp = parent[x];
    11     parent[x] = GetRoot(parent[x]); 
    12     R[x] = (R[x] + R[tmp]) % 3; //递归过程会计算出R[tmp]
    13     return parent[x];
    14 }
    15 
    16 void merge(int a1, int a2, int ra1, int ra2, int d)
    17 {
    18     parent[ra2] = ra1;                //a2的根接在a1的根下
    19     R[ra2] = ((3 - R[a2]) + d + R[a1]) % 3;
    20 }
    21 
    22 int main()
    23 {
    24     int N, K, r, a1, a2;
    25     long ans = 0;
    26     for (int i = 0; i < 50005; i++) parent[i] = i;
    27     cin >> N >> K;
    28     while (K--) {
    29         cin >> r >> a1 >> a2;
    30         if ((a1 == a2 && r == 2) || a1 > N || a2 > N) ans++;
    31         else {
    32             int ra1 = GetRoot(a1);
    33             int ra2 = GetRoot(a2);
    34             if (ra1 != ra2) merge(a1, a2, ra1, ra2, r - 1);
    35             else {
    36                 switch (r) {
    37                 case 1:
    38                     if (R[a1] != R[a2])ans++;
    39                     break;
    40                 case 2:
    41                     if (((3 - R[a1] + R[a2]) % 3) != 1)ans++; //想清楚“向量”的方向
    42                     break;
    43                 }
    44             }
    45         }
    46     }
    47     cout << ans << endl;
    48     return 0;
    49 }
  • 相关阅读:
    第十二章学习笔记
    UVa OJ 107 The Cat in the Hat (戴帽子的猫)
    UVa OJ 123 Searching Quickly (快速查找)
    UVa OJ 119 Greedy Gift Givers (贪婪的送礼者)
    UVa OJ 113 Power of Cryptography (密文的乘方)
    UVa OJ 112 Tree Summing (树的求和)
    UVa OJ 641 Do the Untwist (解密工作)
    UVa OJ 105 The Skyline Problem (地平线问题)
    UVa OJ 100 The 3n + 1 problem (3n + 1问题)
    UVa OJ 121 Pipe Fitters (装管子)
  • 原文地址:https://www.cnblogs.com/Jeffrey-Y/p/9668022.html
Copyright © 2011-2022 走看看