• 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 }
  • 相关阅读:
    UWP关于图片缓存的那些破事儿
    UWP中的文件相关操作
    数据结构-快速排序(C#实现)
    C#与Swift异步操作的差异
    Windows环境下使用Clover四叶草引导双硬盘安装OSX 10.11.5原版镜像
    Winform以任意角度旋转PictureBox中的图片的方法
    Xcode调用旧版本库出现Undefined symbols for architecture x86_64: ld: symbol(s) not found for architecture x86_64
    做WP程序时遇到的一些问题及解决方法
    WInform关闭程序的几种方法以及区别。
    显示在标题上的进度条
  • 原文地址:https://www.cnblogs.com/Jeffrey-Y/p/9668022.html
Copyright © 2020-2023  润新知