并查集——poj1703(带权并查集入门)

传送门:Find them, Catch them

题意警察抓获N个罪犯,这些罪犯只可能属于两个团伙中的一个,现在给出M个条件(D a b表示a和b不在同一团伙),对于每一个询问(A a b)确定a,b是不是属于同一团伙或者不能确定。

思路:如果父亲和孩子是同一个团伙,那么孩子标记为0,如果不是的话,孩子标记为1,然后就是种类并查集的事情。

  • 种类并查集
  • 判断在不同的集合
  • 以前接触的并查集都是让我们判断是否属于同一个连通分量,但这道题却让你判断是否属于同一类

r[x]:x所属的类

具体解释

点击1

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 100005;
int n,m;
int a,b,ans;
int pre[maxn];			//存父亲节点
int r[maxn];			//存与根节点的关系,0 代表同类, 1代表不同类
//r[i]=1 表示结点i与根结点属于一类 
void init()
{
	for(int i=1;i<=n;i++){
		pre[i] = i;		//自己是自己的父亲 
		r[i] = 0;	    //自己与自己是同一类 
	}
}

int find(int x)
{
	if(x == pre[x])	return x;
	
	int t = pre[x];		//记录父亲节点,方便下面更新r[] 
	pre[x] = find(t);
	r[x] = (r[x]+r[t])%2;	//根据子节点与父亲节点的关系和父节点与爷爷节点的关系,推导子节点与爷爷节点的关系 
	return pre[x];		
}

void unite(int x,int y)
{
	int rx = find(x);
	int ry = find(y);
	if(rx != ry){
		pre[rx] = ry;		//合并 
		r[rx] = (r[x]+1-r[y])%2;	//fx与x关系 + x与y的关系 - y与fy的关系 = fx与fy的关系  
	}
}

int main()
{
	int T;
	cin>>T;
	while(T--){
		scanf("%d%d",&n,&m);
		init();
		int flag=0;
		while(m--){
			char str[10];
			scanf("%s%d%d",str,&a,&b);
			if(str[0] == 'A'){
				//如果根节点相同,则表示能判断关系
				if(find(a)==find(b)){
					if(r[a] == r[b])	
						cout<<"In the same gang.\n";
					else
						cout<<"In different gangs.\n";
				}
				else{
					cout<<"Not sure yet.\n";
				}
			}
			if(str[0] == 'D'){
				unite(a,b);
			}
		}
	}
	return 0;
}

 

posted @ 2017-08-10 14:21  GGBeng  阅读(208)  评论(0编辑  收藏  举报