POJ 1182 食物链(种类并查集)
Posted Yeader
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 1182 食物链(种类并查集)相关的知识,希望对你有一定的参考价值。
题目链接:http://poj.org/problem?id=1182
题目大意:有N只动物,分别编号为1~N,所有动物都属于A,B,C中的其中一种。已知A吃B、B吃C、C吃A。按顺序给出下面的两种信息共K条。
第一种,x和y属于同一种类。
第二种,x吃y。
当这些信息满足以下任意一个条件时,该信息为假信息:
① 当前的话与前面的某些真的话冲突,就是假话。
② 当前的话中X或Y比N大,就是假话。
③ 当前的话表示X吃X,就是假话。
需要你判断一共有多少条信息是假的。
解题思路:
解法一:数组扩增三倍用来表示A,B,C。这种解法我是在《挑战程序设计》上看的,感觉是我比较好理解的版本。下面都是书上的原话:
对于每只动物x创建3个元素,i-A,i-B,i-C,并用这3*N个元素建立并查集。这个并查集维护如下信息:
①i-x,i属于种类x。
②并查集里的每一组表示组内所有元素代表的情况都同时发生或不发生。
例如,如果i-A和j-B在同一个组里,就表示如果i属于种类A那么j一定属于种类B,如果j属于种类B那么i一定属于种类A。因此,对于每一条信息,只需要按照下面进行操作就可以了。
1)第一种,x和y属于同一种类........合并x-A和y-A、x-B和y-B、x-C和y-C。
2)第二种,x吃y.......合并x-A和y-B、x-B和y-C、x-C和y-A。
不过在合并之前,需要先判断合并是否会产生矛盾。例如第一种信息的情况下,需要检查比如x-A和y-B或者y-C是否在同一组等信息。
代码:
1 #include<cstdio> 2 const int N=5e4+5; 3 4 int root[N*3]; 5 6 int find(int x){ 7 return root[x]==x?x:root[x]=find(root[x]); 8 } 9 10 bool same(int a,int b){ 11 return find(a)==find(b); 12 } 13 14 void unite(int a,int b){ 15 if(find(a)!=find(b)) 16 root[find(a)]=find(b); 17 } 18 19 //元素x,x+N,x+2*N分别代表x-A,x-B,x-C 20 int main(){ 21 int N,K,ans=0; 22 scanf("%d%d",&N,&K); 23 for(int i=1;i<=3*N;i++){ 24 root[i]=i; 25 } 26 while(K--){ 27 int t,x,y; 28 scanf("%d%d%d",&t,&x,&y); 29 if(x>N||y>N){ 30 ans++; 31 continue; 32 } 33 if(t==1){ 34 //"x,y属于同一类" 的信息 35 if(same(x,y+N)||same(x,y+2*N)) 36 ans++; 37 else{ 38 unite(x,y); 39 unite(x+N,y+N); 40 unite(x+2*N,y+2*N); 41 } 42 } 43 else{ 44 //"x吃y"的信息 45 if(same(x,y)||same(x,y+2*N)) 46 ans++; 47 else{ 48 unite(x,y+N); 49 unite(x+N,y+2*N); 50 unite(x+2*N,y); 51 } 52 } 53 } 54 printf("%d\n",ans); 55 }
以上是关于POJ 1182 食物链(种类并查集)的主要内容,如果未能解决你的问题,请参考以下文章
带权并查集(含种类并查集)经典模板 例题:①POJ 1182 食物链(经典)②HDU - 1829 A bug's life(简单) ③hihoCoder 1515 : 分数调查(示例代码(代