首页 > 代码库 > [并查集] POJ 1182 食物链

[并查集] POJ 1182 食物链

食物链
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 66294   Accepted: 19539

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

100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

Sample Output

3

Source

Noi 01
解题思路1: 挑战上给的思路是为每个动物创建A,B,C三个元素,A种元素代表他们自己本源,B种元素代表吃他们自己的集合,C种元素代表他们吃的动物的集合。这样我们就可以                  用三种集合间的关系来进行求解。详情请见挑战的P89。
解题思路2:但是,网上有前辈用向量的方式做出了这一道题,为带权并查集的求解展开了新的思路。
                首先我们看一下此题是否满足向量间的关系,由于加法可以变为减法,我们只需要验证加法,就可以验证减法。
                首先,同族的关系是0,于是任何数+0是它本身。明显的是吃与被吃对同族的影响是一样的,满足0向量的加减法。
                其次,1+1=2,原题有重要的提示就算A吃B,B吃C,C吃A,也就是说,1+1仍然满足向量加法且符合题意。
                在之后,验证1+2,2+2我们可以发现%3后组成了一个向量的循环,也就是说,此题是可以大胆用向量来解的。
代码:
#include<stdio.h>
int father[51010],relation[51010];
void init(int n)
  {
  	int i;
  	for(i=1;i<=n;++i) father[i]=i;
  	for(i=1;i<=n;++i) relation[i]=0;
  }
int find(int x)
  {
  	 if(x==father[x]) return (x);
  	 int t=father[x];
  	 father[x]=find(father[x]);
  	 relation[x]=(relation[x]+relation[t])%3;
  	 return (father[x]);
  }
void merge(int x,int y,int z)
  {
  	 int find_x=find(x);
  	 int find_y=find(y);
  	 if(find_x!=find_y)
  	   {
  	   	  relation[find_x]=(z-1+relation[y]-relation[x]+3)%3;
  	   	  father[find_x]=find_y;
	   }
  }
int main()
  {
  	 int n,m,relat,x,y,ans=0;
  	 scanf("%d%d",&n,&m);
  	 init(n);
  	 while(m--)
  	   {
  	   	  scanf("%d%d%d",&relat,&x,&y);
  	   	  if(x>n||y>n||(relat==2&&x==y)) 
  	   	    {
  	   	       ++ans;
  	   	       continue;
			}else
		  if(find(x)!=find(y))
		    {
		       merge(x,y,relat);
		       continue;
			}else
		  if(find(x)==find(y))
		    {
		       if(relat==1)
		         {
		         	if(relation[x]!=relation[y]) 
					 {
					   ++ans;
					   continue;
                     }
				 }else
			   if(relat==2)
			     {
			     	if((relation[x]-relation[y]+3)%3!=1) 
					 {
					   ++ans;
					   continue;
				     }
				 }
			}
	   }
	 printf("%d\n",ans);
	 return 0;
  }

  

[并查集] POJ 1182 食物链