传送门

食物链 
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 65579   Accepted: 19336

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

  1. 100 7
  2. 1 101 1
  3. 2 1 2
  4. 2 2 3
  5. 2 3 3
  6. 1 1 3
  7. 2 3 1
  8. 1 5 5

Sample Output

  1. 3

思路

解法一:来自《挑战程序设计竞赛》

由于N和K很大,所以必须高效地维护动物之间的关系,并快速判断是否产生了矛盾。并查集是维护 “属于同一组” 的数据结构,但是在本题中,并不只有属于同一类的信息,还有捕食关系的存在。因此需要开动脑筋维护这些关系。

对于每只动物i创建3个元素i-A, i-B, i-C, 并用这3*N个元素建立并查集。这个并查集维护如下信息:

  • i-x 表示 “i属于种类x”。
  • 并查集里的每一个组表示组内所有元素代表的情况都同时发生或不发生。

例如,如果i-Aj-B在同一个组里,就表示如果i属于种类A那么j一定属于种类B,如果j属于种类B那么i一定属于种类A。因此,对于每一条信息,只需要按照下面进行操作就可以了。

  • 第一种,x和y属于同一种类———合并x-A和y-A、x-B和y-B、x-C和y-C。
  • 第二种,x吃y—————————合并x-A和y-B、x-B和y-C、x-C和y-A。

不过在合并之前需要先判断合并是否会产生矛盾。例如在第一种信息的情况下,需要检查比如x-Ay-B或者y-C是否在同一组等信息。

 解法二:加权并查集

思路来源于:click here

Part I - 权值(relation)的确定。

    注:每个节点对应的 relation[]值记录他与根节点的关系:

      我们根据题意,森林中有3种动物。A吃B,B吃C,C吃A。
    我们还要使用并查集,那么,我们就以动物之间的关系来作为并查集每个节点的权值。
    注意,我们不知道所给的动物(题目说了,输入只给编号)所属的种类。

    所以,我们可以用动物之间“相对”的关系来确定一个并查集。

    • 0 - 这个节点与它的父节点是同类
    • 1 - 这个节点被它的父节点吃
    • 2 - 这个节点吃它的父节点

    注意,这个0,1,2所代表的意义不是随便制定的,我们看题目中的要求。
    输入的时候,第一个数字(下文中,设为d)指定了后面两种动物的关系:

    • 1 - X与Y同类
    • 2 - X吃Y

    我们注意到:

    • 如果d == 1 则 x 和 y 是同类 ,那么 y 对 x 的关系是 0
    • 如果d == 2 则 x 吃了 y, 那么 y 对 x 的关系是 1, x 对 y 的关系是 2.
    • 综上所述 ,无论 d为1 或者是为 2,  y 对 x 的关系都是 d-1

    所以,这个0,1,2不是随便选的

Part II - 路径压缩,以及节点间关系确定
    确定了权值之后,我们要确定有关的操作。
    我们把所有的动物全初始化 relation[i]=0,f[i]=i

    (1)路径压缩时的节点算法

    通过穷举我们可以发现

      f[now]=f[f[now]]

      relation[now]=(relation[now]+relation[f[now]]) % 3

    这个路径压缩算法是正确的
    关于这个路径压缩算法,还有一点需要注意的地方,我们一会再谈
    注意,根据当前节点的relation和当前节点父节点的relation推出
    当前节点与其父节点的父节点的relation这个公式十分重要!!
    它推不出来下面都理解不了!!自己用穷举法推一下:
    好吧,为了方便伸手党,我给出穷举过程
                 i      j
        爷爷  父亲 儿子      儿子与爷爷
           0      0      (i + j)%3 = 0
           0      1      (i + j)%3 = 1
           0      2      (i + j)%3 = 2
           1      0      (i + j)%3 = 1
           1      1      (i + j)%3 = 2
           1      2      (i + j)%3 = 0
           2      0      (i + j)%3 = 2
           2      1      (i + j)%3 = 0
           2      2      (i + j)%3 = 1
    这样可以看到,( 儿子relation + 父亲relation ) % 3 = 儿子对爷爷的relation

    所以有relation[now]=(relation[now]+relation[f[now]]) % 3
    这就是路径压缩的节点算法

    (2) 集合间关系的确定

        当确定D X Y 的关系的正确性后,要把二者的集合合并为一个集合。就是把Y的集合的根节点其父亲设置为X的集合的根节点。

        y的根节点与x的根节点间的关系(即fy与fx的关系):
        relation[find(y)]=(3-relation[y]+(d-1)+relation[x]) % 3;
        这个公式,是分三部分,这么推出来的:
        ( d - 1 ) :这是X和Y之间的relation,X是Y的父节点时,Y的relation就是这个
        3 - relation[y] = 根据Y与根节点的关系,逆推根节点与Y的关系
        这部分也是穷举法推出来的,我们举例:
              0(父子同类)( 3 - 0 ) % 3 = 0
              1(父吃子) ( 3 - 1 ) % 3 = 2  //父吃子
              2(子吃父) ( 3 - 2 ) % 3 = 1  //子吃父

        所以有y的父结点与x的父结点关系relation[find(y)]=(3-relation[y]+(d-1)+relation[x]) % 3;
        注意,这个当所有集合都是初始化状态的时候也适用

Part III - 判断   

      每次输入一组数据 d, x, y判断是否超过 N 后,先通过find()函数找他们的根节点从而判断他们是否在同一棵树中。(也就是是否有确定的关系)

      1.如果在同一棵树中find(x) == find(y):直接判断是否说谎。

      1)如果 d ==1,那么 x 与 y 应该是同类,他们的r[]应该相等,如果不相等,则说谎数 +1

      2)如果 d==2,那么 x 应该吃了 y,也就是 (r[x]+1)%3 == r[y]如果不满足,则说谎数 +1

         如何判断 x 吃了 y 是  (r[x]+1)%3 == r[y],请看下图:(PS:箭头方向指向被吃方)

      2.如果不在同一棵树中:那么合并 x 与 y 分别所在的树。

        合并树时要注意顺序,我这里是把 x 树的根当做主根,否则会WA的很惨

        再次提醒:找父亲节点时,要不断更新 r[]的值。这里有一个关系:如果 x 和y 为关系 r1, y 和 z 为关系 r2,那么 x 和z的关系就是 (r1+r2)%3,证明过程上面已经论证过了。

  1. #include<stdio.h>
  2. #include<string.h>
  3. const int maxn = 50005;
  4. int N,fa[maxn*3];
  5.  
  6. int find(int x)
  7. {
  8. int r = x;
  9. while (r != fa[r]) r = fa[r];
  10. int i = x,j;
  11. while (i != r)
  12. {
  13. j = fa[i];
  14. fa[i] = r;
  15. i = j;
  16. }
  17. return r;
  18. }
  19.  
  20. void unite(int x,int y)
  21. {
  22. x = find(x),y = find(y);
  23. if (x != y) fa[x] = y;
  24. }
  25.  
  26. bool same(int x,int y)
  27. {
  28. return find(x) == find(y);
  29. }
  30.  
  31. int main()
  32. {
  33. int K,D,X,Y,res = 0;
  34. scanf("%d%d",&N,&K);
  35. for (int i = 1;i <= 3*N;i++) fa[i] = i;
  36. while (K--)
  37. {
  38. scanf("%d%d%d",&D,&X,&Y);
  39. if (X < 1 || X > N || Y < 1 || Y > N)
  40. {
  41. res++;
  42. continue;
  43. }
  44. if (D == 1)
  45. {
  46. if (same(X,Y+N) || same(X,Y+2*N)) res++;
  47. else unite(X,Y),unite(X+N,Y+N),unite(X+2*N,Y+2*N);
  48. }
  49. else if (D == 2)
  50. {
  51. if (same(X,Y) || same(X,Y+2*N)) res++;
  52. else unite(X,Y+N),unite(X+N,Y+2*N),unite(X+2*N,Y);
  53. }
  54. }
  55. printf("%d\n",res);
  56. return 0;
  57. }
 
  1. #include<stdio.h>
  2. const int maxn = 50005;
  3. int r[maxn],fa[maxn];
  4.  
  5. int find(int x)
  6. {
  7. if (x == fa[x]) return fa[x];
  8. int tmp = fa[x];
  9. fa[x] = find(fa[x]);
  10. r[x] = (r[x] + r[tmp])%3;
  11. return fa[x];
  12. }
  13.  
  14. void unite(int x,int y,int d)
  15. {
  16. int fx = find(x),fy = find(y);
  17. fa[fy] = fx; //y被x吃,所以以x作为y的根节点
  18. r[fy] = (r[x] - r[y] + 3 + (d - 1))%3;
  19. }
  20.  
  21. int main()
  22. {
  23. int N,K,X,Y,D,res = 0;
  24. scanf("%d%d",&N,&K);
  25. for (int i = 1;i <= N;i++) r[i] = 0,fa[i] = i;
  26. while (K--)
  27. {
  28. scanf("%d%d%d",&D,&X,&Y);
  29. if (X > N || Y > N ||(X == Y && D == 2)) res++;
  30. else if (find(X) == find(Y))
  31. {
  32. if (D == 1 && r[X] != r[Y]) res++;
  33. if (D == 2 && (r[X] + 1) % 3 != r[Y]) res++;
  34. }
  35. else unite(X,Y,D);
  36. }
  37. printf("%d\n",res);
  38. return 0;
  39. }

  

POJ 1182 食物链(带权并查集)的更多相关文章

  1. poj 1182 食物链 带权并查集

    食物链是并查集的进阶运用的一道非常经典的题目. 题目如下: 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A, ...

  2. POJ 1182 食物链 (带权并查集 && 向量偏移)

    题意 : 中文题就不说题意了…… 分析 : 通过普通并查集的整理归类, 能够单纯地知道某些元素是否在同一个集合内.但是题目不仅只有种类之分, 还有种类之间的关系, 即同类以及吃与被吃, 而且重点是题目 ...

  3. K - Find them, Catch them POJ - 1703 (带权并查集)

    题目链接: K - Find them, Catch them POJ - 1703 题目大意:警方决定捣毁两大犯罪团伙:龙帮和蛇帮,显然一个帮派至少有一人.该城有N个罪犯,编号从1至N(N<= ...

  4. POJ - 2912 Rochambeau (带权并查集+枚举)

    题意:有N个人被分为了三组,其中有一个人是开了挂的.同组的人的关系是‘=’,不同组的人关系是‘<’或'>',但是开了挂的人可以给出自己和他人任意的关系.现在要根据M条关系找出这个开了挂的人 ...

  5. A Bug's Life POJ - 2492 (带权并查集)

    A Bug's Life POJ - 2492 Background Professor Hopper is researching the sexual behavior of a rare spe ...

  6. poj1182 食物链 带权并查集

    题目传送门 题目大意:大家都懂. 思路: 今天给实验室的学弟学妹们讲的带权并查集,本来不想细讲的,但是被学弟学妹们的态度感动了,所以写了一下这个博客,思想在今天白天已经讲过了,所以直接上代码. 首先, ...

  7. poj 1182:食物链(种类并查集,食物链问题)

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 44168   Accepted: 12878 Description ...

  8. POJ 1182 食物链(种类并查集)

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 63592   Accepted: 18670 Description ...

  9. poj 1182 食物链(关系并查集)

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 62824   Accepted: 18432 Description ...

  10. POJ 1182 食物链 (种类并查集)

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种.有人用两种说 ...

随机推荐

  1. lecture6-mini批量梯度训练及三个加速的方法

    Hinton的第6课,这一课中最后的那个rmsprop,关于它的资料,相对较少,差不多除了Hinton提出,没论文的样子,各位大大可以在这上面研究研究啊. 一.mini-批量梯度下降概述 这部分将介绍 ...

  2. 简单高效的nodejs爬虫模型

    这篇文章讲解一下yunshare项目的爬虫模型. 使用nodejs开发爬虫很简单,不需要类似python的scrapy这样的爬虫框架,只需要用request或者superagent这样的http库就能 ...

  3. 为什么我们的web前端变的越来越复杂

    前端发展了也有些年头了,曾记得很多年前,聊起前端,都觉得是很简单,那个时候都没有前端工程师这个职位.可现在,前端已经逆袭了,已经不是原来的样子了,各种技术层出不穷,显的越来越高深莫测了.前端真的变得那 ...

  4. iOS--cocopod升级新版本

    上面那个也可安装.cocopod

  5. error_reporting()

    定义和用法 error_reporting() 设置 PHP 的报错级别并返回当前级别. 语法 error_reporting(report_level) 如果参数 level 未指定,当前报错级别将 ...

  6. asp.net mvc 多级目录结构

    ikmb@163.com ASP.NET MVC默认的文件组织和URL访问都是一级,我们通常要将一个功能模块组织到一个目录下.方法是:1.文件组织 分别在Controllers和Views文件夹下建议 ...

  7. Js-动态控制table的tr、td增加及删除的具体实现

    <table id='wifi_clients_table' style="color:#0099CC;font-size:12px;" class="table ...

  8. MathType给公式加三角着重号的方法

    MathType是一款出色的数学公式编辑器,不仅可以兼容word,还与PPT也兼容.它也可以在PPT中编辑出非常漂亮的公式,再加上PPT本身所具有的动画.颜色.显示等功能,在演示数学公式时非常的精美. ...

  9. java内存管理机制

    JAVA 内存管理总结 1. java是如何管理内存的 Java的内存管理就是对象的分配和释放问题.(两部分) 分配 :内存的分配是由程序完成的,程序员需要通过关键字new 为每个对象申请内存空间 ( ...

  10. Yii2 Redis的使用

    Yii2 redis扩展    下载 将下载的解压,改名为redis,放在vendor\yiisoft\yii2\目录下 包含Connection.php,ActiveRecord.php等文件 修改 ...