poj-1703 Find them, Catch them ***

【转】

解析:并查集的题目,并查集的拓展。一般的思路是先初始化,各个数自成一个组,然后是两个gangs自成一个组,但由于两个给定元素有三种关系:  In the same gang;   In different gangs;   Not sure yet; 采用此模型的缺点是判断两个元素关系还未确定这种情况比较复杂,故模型需要改进。本题的正确模型是将已经确定关系的元素组成一个集合,然后利用两个元素的 father是同一个来确定这两个元素之间的关系。father[a]中存放的是a的根结点,rank中存放的是father[a]与a的关系,0表示两 者不在同一个gangs中,1表示两者在同一个gangs中。具体的程序还是沿袭了并查集的Make_Set()、Find_Set()、 Union_Set()的三步骤。


心得:并查集有三步是必须的: Make_Set()、Find_Set()、Union_Set()。  rank[a]的改变是伴随着father[a]的改变而更新的(有father改变就有rank改变) ,要是father改变了,而rank未改变,此时的rank就记录了一个错误的值,father未改变(即使实际的father已不是现在的值,但只要father未改变,rank 的值就是“正确”的,认识到这点很重要。),第一次错误就是因为没有考虑清楚这点。




#include<iostream>
#include
<cstdio>

using namespace std;

int father[100000+10]; //表示x的根结点
int rank[100000+10];


void Make_Set(int n){
int i;
for(i=1;i<=n;i++){
father[i]
= i;
rank[i]
= 1;
}
}

int Find_Set(int a){
if(a==father[a])
return a;
else {
int temp = father[a];
father[a]
= Find_Set(father[a]);
rank[a]
= (rank[temp]+rank[a]+1)%2 ;
//必须有,更新路径压缩之后a与根结点之间的关系; father改变,rank就必须要跟着改变
}
return father[a];
}

void Union_Set(int a,int b){
int fa,fb;
fa
= Find_Set(a);
fb
= Find_Set(b);
if(fa!=fb){
father[fa]
= fb;
rank[fa]
= (rank[a]+rank[b])%2 ; //fa结点以下的结点的rank不需要改
}
}

int main(){
//freopen("1in.txt","r",stdin);
//freopen("1out.txt","w",stdout);
int T,N,M;
char ch;
int a,b,fa,fb;
scanf(
"%d",&T);
while(T--){
scanf(
"%d%d",&N,&M);
Make_Set(N);
int i;
for(i=1;i<=M;i++){
getchar();
scanf(
"%c%d%d",&ch,&a,&b);
if(ch=='A'){
if(Find_Set(a)==Find_Set(b)){
//在使用rank之前,已经在用Find_Set函数寻找a的时候将a路径上的所有结点的rank值改变过了
if((rank[a]+rank[b])%2==0){
printf(
"In the same gang.\n");
}
else
printf(
"In different gangs.\n");
}
else{
printf(
"Not sure yet.\n");
}

}
else{
Union_Set(a,b);
}

}

}
return 0;
}

你可能感兴趣的:(catch)