传送门

食物链 
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. python网络编程学习《一》

    最近,刚实习完,很喜欢实验楼,但是自己的方向仍然不能确定,自己觉得可选择的空间很大,尽管已经是大四的人了,想到别人都在忙着买职业装,买高跟鞋面试,学习化妆什么的,看看自己,反而开始慢慢关注运动,食疗以 ...

  2. c++ 头文件

    可以将程序分为二部分: 头文件:包含结构声明和使用这些结构的函数的原型 源代码文件: 包含与结构有关的函数的代码 不要将函数的定义或变量的声明放在头文件里, 一般头文件可以包含以下内容 >函数原 ...

  3. Theano2.1.1-基础知识之准备工作

    来源:http://deeplearning.net/software/theano/tutorial/index.html#tutorial 这里介绍的是使用theano的一些基础知识,虽然thea ...

  4. ASP.NET MVC 中应用Windows服务以及Webservice服务开发分布式定时器

    ASP.NET MVC 中应用Windows服务以及Webservice服务开发分布式定时器一:闲谈一下:1.现在任务跟踪管理系统已经开发快要结束了,抽一点时间来写一下,想一想自己就有成就感啊!!  ...

  5. DirectX11 SDK 例程报错解决方法

    下载好DirectX11例程后,VS2015运行不起来,好几个报错 在这里记录一下,虽然挺简单的,但是我想对于像我这样的新手小伙伴们来说还是挺有用的 第一个错误: FXC : error X3501: ...

  6. ASP.NET MVC3入门教程之ajax交互

    本文转载自:http://www.youarebug.com/forum.php?mod=viewthread&tid=100&extra=page%3D1 随着web技术的不断发展与 ...

  7. 项目分布式部署那些事(1):ONS消息队列、基于Redis的Session共享,开源共享

    因业务发展需要现在的系统不足以支撑现在的用户量,于是我们在一周之前着手项目的性能优化与分布式部署的相关动作. 概况 现在的系统是基于RabbitHub(一套开源的开发时框架)和Rabbit.WeiXi ...

  8. 在SQL Server 2012中实现CDC for Oracle

    在上篇在SSIS 2012中使用CDC(数据变更捕获)中,介绍了如何在SSIS 2012中使用CDC,本文在此基础上介绍,如何通过Attunity提供的Change Data Capture Desi ...

  9. 高仿Windows Phone QQ登录界面

    给 TextBox文本框前添加图片 扩展PhoneTextBox:添加一个类"ExtentPhoneTextBox"继承 PhoneTextBox ,在"ExtentPh ...

  10. SQLite剖析之体系结构

    1.通过官方的SQLite架构文档,理清大体的系统层次:Architecture of SQLite 2.阅读SQLite Documentation中Technical/Design Documen ...