• [并查集] 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

    解题思路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
    ",ans);
    	 return 0;
      }
    

      

  • 相关阅读:
    mark
    ON DUPLICATE KEY UPDATE重复插入时更新
    lnmp上传文件
    websoket
    Nginx 和 Php 优化
    Nginx常见问题
    Keepalived 高可用
    https ; 及https证书
    Nginx动静分离;资源分离;rewrite重写、跳转、伪静态、规则、日志
    nginx负载均衡会话保持;四层负载均衡;端口转发
  • 原文地址:https://www.cnblogs.com/fuermowei-sw/p/6193521.html
Copyright © 2020-2023  润新知