POJ - 1703 Find them, Catch them (并查集)

                  POJ - 1703  Find them, Catch them (并查集)

        这道题与食物链那一道题是同一类型的,但稍微简单些           

        比普通的并查集多了一个relation [i]数组,记录与父亲节点的关系,在并查集里的元素都是已经它们之间的关系的,在路径压缩集合合并时不断的更新relation数组

       r[i]=0代表与父节点同类,r[i]=1代表异类,初始化为同类

      下面推导如何在路径压缩时更新关系:

      根据子节点与父亲节点的关系和父节点与爷爷节点的关系,推导子节点与爷爷节点的关系

  枚举出来所有情况,找出规律(r1+r2)%2或者 r1==r2? 0:1

        (a, b) (b, c)  (a, c)  (r1+r2)%2
          0	      0         0           0        a 和 b是同类 , b 和 c 是同类, 所以 a 和 c 也是同类
          0          1         1           1        a 和 b是同类 , b 和 c 是异类, 所以 a 和 c 也是异类
          1          0         1           1        a 和 b是异类 , b 和 c 是同类, 所以 a 和 c 是异类
          1          1         0           0        a 和 b是异类 , b 和 c 是异类, 所以 a 和 c 是同类
         在集合合并时也可以枚举,同样用矢量运算也可以求得
       
#include<stdio.h>
const int MAXN=100005;
int pre[MAXN],re[MAXN];
int n,m;
int ans;
void init()
{
	for(int i=1;i<=n;i++){
		pre[i]=i;
		re[i]=0;//初始时父节点为本身,当然同类,初始为0 
	}
}
int find(int x) //找根节点 
{
	if(x!=pre[x]){
		int t=pre[x]; //记录下父亲节点,方便以下更新 
		pre[x]=find(pre[x]);//根据子节点与父亲节点的关系和父节点与爷爷节点的关系,推导子节点与爷爷节点的关系 
		r[x] = (r[x]+r[t])%2; ;
	}
	return pre[x];
}
void merge(int x,int y)
{
	//找到x与y的根节点 
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy){
		pre[fy]=fx;//合并 
		r[fx] = (r[x]+1+r[y])%2;// //fx与x关系 + x与y的关系 + y与fy的关系 = fx与fy的关系 
	}
}
int main(void)
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
	    scanf("%d%d",&n,&m);
	    char op[2];
	    int x,y;
	    init();
	    while(m--){
		     scanf("%s%d%d",op,&x,&y);
		     if(op[0]=='A') 
		     {
		     	if(find(x)!=find(y)){//不在同一棵树里,所以不确定 
		     	  printf("Not sure yet.\n");
		     	  continue;
		        }
		     	if(re[x]==re[y])
		     	  printf("In the same gang.\n");
		     	else
				  printf("In different gangs.\n");
		     }
		     else
		         merge(x,y);
        }
	}
	return 0;
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值