• POJ 1182 食物链 【并查集】


    解题思路:首先是没有思路的----然后看了几篇解题报告

                  http://blog.csdn.net/ditian1027/article/details/20804911

                  http://poj.org/showmessage?message_id=152847

                  http://blog.163.com/jiazheng2222%40126/blog/static/16963238320101258935104/

    这是discuss里面的一篇分析---

     http://poj.org/showmessage?message_id=152847
     我的理解是,对于集合里的任意两个元素a,b而言,它们之间必定存在着某种联系,
    > 
    > 因为并查集中的元素均是有联系的,否则也不会被合并到当前集合中。那么我们
    > 
    > 就把这2个元素之间的关系量转化为一个偏移量,以食物链的关系而言,不妨假设
    > 
    > a->b 偏移量0时 a和b同类
    > 
    > a->b 偏移量1时 a吃b
    > 
    > a->b 偏移量2时 a被b吃,也就是b吃a
    > 
    > 有了这些基础,我们就可以在并查集中完成任意两个元素之间的关系转换了。
    > 
    > 不妨继续假设,a的当前集合根节点aa,b的当前集合根节点bb,a->b的偏移值为d-1(题中给出的询问已知条件)
    > 
    > (1)如果aa和bb不相同,那么我们把bb合并到aa上,并且更新delta[bb]值(delta[i]表示i的当前集合根节点到i的偏移量)
    > 
    >     此时 aa->bb = aa->a + a->b + b->bb,可能这一步就是所谓向量思维模式吧
    > 
    >     上式进一步转化为:aa->bb = (delta[a]+d-1+3-delta[b])%3 = delta[bb],(模3是保证偏移量取值始终在[0,2]间)
    > 
    > (2)如果aa和bb相同,那么我们就验证a->b之间的偏移量是否与题中给出的d-1一致
    > 
    >     此时 a->b = a->aa + aa->b = a->aa + bb->b,
    > 
    >     上式进一步转化为:a->b = (3-delta[a]+delta[b])%3,
    > 
    >     若一致则为真,否则为假。
    > 
    > 希望可以对LS有所帮助 :]
    

      

                  下面是自己的体会

    pre[x]:表示x的父节点为pre[x]
    p=find(x),其中p表示x的根节点
    relation[x] :表示节点x与其根节点的关系,
                 relation[x]=p->x(因为后面要用到向量,所以先把向量的方向说明出来,relation[x]向量代表从根节点p指向x的向量)
                 relation[x]=0 表示p与x同类
                 relation[x]=1 表示p吃x
    			 relation[x]=2 表示x吃p 
    ----------------------------------------------------------------------------------- 
    对于给定的一句话 d,x,y
     先判断x,y是否在同一个集合关系(集合是按照能够判断x,y关系来划分的)
     if(x,y在同一个集合)
     {
     	判断说的这句话的真假 ;
     } 
     else
     {
     	这句话认为为真,将x,y合并起来;
     }
    ----------------------------------------------------------------------------------- 
     判断一句话的 真假可以有两种办法
     (方法一)直接列出所有为真的情况,如果这句话不符合列举出的所有情况,则这句话为假
     1)
     d==1 表示x,y为同类 
     relation[x]    relation[y]
        0               0
        1               1
        2               2
    所以如果relation[x]!=relation[y],则这句话为假话
    2)
    d==2 表示x吃y
    relation[x]    relation[y]
        0               2     //此时x与根节点同类,要让x吃y,relation[y]=2 
        2               1     //此时x吃根节点,要让x吃y,则y与根节点同类,relation[y]=1 
        1               0     //此时x被根节点吃,要让x吃y,则y应该吃根节点,relation[y]=1
    如果不满足这三组对应的 值,则 这句话为假
    
    
    (方法二)
    详细见 http://poj.org/showmessage?message_id=152847
    按照向量来做
    x->y=x->p+p->y//因为此时p=q,所以可以将p换成q
        =-relation[x]+relation [y]
        =relation[y]-relation[x]//再进一步处理,为了防止为表达式的值为负数,给它加上3,
    	=(relation[y]-relation[x]+3)%3 // 为使表达式的值在0到2之间,给表达式模 上3
    又因为题目中给的是 d==1 x,y为同类,对应于我们规定的同类为0,应该将d-1
    所以判断我们计算出的偏移量和说的那句话的偏移量是否一致,如果不一致,则说的 假话
    即
    ((relation[y]-relation[x]+3)%3) !=d-1,则这句话为假话
    
    --------------------------------------------------------------------------------------- 
      p,q不同时  合并 x,y
    将q合并到p上,同时更新relation[q] 
    p->q=p->x+x->y+y->q
        =relation[x]+(d-1) +(-relation[y])//同样为防止表达式的值为负,加上3 
        =(relation[x]-relation[y]+(d-1)+3) %3//为了使表达式的值在0到2之间,模上3 
    即 relation[q]=(relation[x]-relation[y]+(d-1)+3) %3
    
    ----------------------------------------------------------------------------------------
    压缩路径的时候,同时更新relation[]数组
    详细见:http://blog.csdn.net/ditian1027/article/details/20804911
    现在知道儿子节点x, 父亲节点 fx,爷爷节点ffx,要求ffx->x
    则 ffx->x=ffx->fx+fx->x
             =relation[fx]+relation[x]
    
    即 relation[x]=(relation[x]+relation[tmp])%3 
    将fx记作x的亲生父亲,又因为find()函数是带路径压缩的,经过压缩后,x的父亲节点变为fx',不能用来计算 
    而我们需要的是fx的值 ,所以用tmp将它记录下来,再压缩
    ---------------------------------------------------------------------------------------- 
    

      反思:用向量表示relation[]数组时,向量起点和向量的终点一定要搞清楚,要不然后面的式子符号就会不对

    下面是两种不同判断说话真假的代码

    #include<stdio.h>
    #define maxn 50010
    int pre[maxn],relation[maxn];
    int find(int a)
    {
    	int tmp;
    	tmp=pre[a];
    	if(a!=pre[a])
    	pre[a]=find(pre[a]);
    	relation[a]=(relation[a]+relation[tmp])%3;
    	return pre[a];
    }
    
    void unionroot(int x,int y,int d)
    {
    	int p,q;
    	p=find(x);
    	q=find(y);
    	pre[q]=p;
    	relation[q]=(relation[x]-relation[y]+3+d-1)%3;
    }
    
    int main()
    {
    	int i,n,k,sum,x,y,p,q,d;
    	scanf("%d %d",&n,&k);
    		for(i=0;i<=maxn;i++)
    		{
    			pre[i]=i;
    			relation[i]=0;
    		}
    		sum=0;
    		while(k--)
    		{
    			scanf("%d %d %d",&d,&x,&y);
    			p=find(x);
    			q=find(y);
    			if((x>n||y>n)||(x==y&&d==2))
    			{
    			sum++;
    			continue;
    		    }
    			if(p==q)
    			{
    				if((relation[y]-relation[x]+3)%3!=d-1)
    					 sum++;
    			}
    				else
    				unionroot(x,y,d);
    		}
    		printf("%d
    ",sum);
    }
    

      

    #include<stdio.h>
    #define maxn 50010
    int pre[maxn],relation[maxn];
    int find(int a)
    {
    	int tmp;
    	tmp=pre[a];
    	if(a!=pre[a])	
    	pre[a]=find(pre[a]);
    	relation[a]=(relation[a]+relation[tmp])%3;
    	return pre[a];		
    }
    
    void unionroot(int x,int y,int d)
    {
    	int p,q;
    	p=find(x);
    	q=find(y);
    	pre[p]=q;
    	relation[p]=(relation[y]-relation[x]+3+d-1)%3;
    }
    
    int main()
    {
    	int i,n,k,sum,x,y,p,q,d;
    	scanf("%d %d",&n,&k);
    		for(i=0;i<=maxn;i++)
    		{
    			pre[i]=i;
    			relation[i]=0;
    		}
    		sum=0;
    		while(k--)
    		{
    			scanf("%d %d %d",&d,&x,&y);
    			p=find(x);
    			q=find(y);
    			if((x>n||y>n)||(x==y&&d==2))
    			{
    			sum++;
    			continue;
    		    }	
    			if(p==q)				
    			{
    				if(d==1&&relation[x]!=relation[y])
    				++sum;
    				if(d==2)
    				{
    					if(relation[x]==0&&relation[y]!=2)
    					++sum;
    					if(relation[x]==1&&relation[y]!=0)
    					++sum;
    					if(relation[x]==2&&relation[y]!=1)
    					++sum;					
    				}
    								
    				
    			}
    				else  
    				unionroot(x,y,d);
    		}
    		printf("%d
    ",sum);
    }
    

      

  • 相关阅读:
    2018北京网络赛 G The Mole /// 分块暴力 点线距离
    POJ 3525 /// 半平面交 模板
    买不到的数目 /// 结论公式 oj26316
    Number Sequence /// oj21456
    Round Numbers /// 组合计数 oj21455
    POJ 1265 /// 皮克定理+多边形边上整点数+多边形面积
    fread 快速读入 (神奇挂!)
    HDU6395(分段+矩阵快速幂)
    如何得出保留某位小数,不进行四舍五入
    Codeforces1114 D. Flood Fill (DP)(整个区间染成同色)
  • 原文地址:https://www.cnblogs.com/wuyuewoniu/p/4205791.html
Copyright © 2020-2023  润新知