昂,poj终于在三天前修复了,这题也终于交掉了,这题自己思考种类并查集的,出了不少的错误,也正因为这些错误让我对种类并查集的理解更加的深刻~继续努力吧
题目链接:http://poj.org/problem?id=1703
题目大意:警察抓了两个帮派(龙帮和蛇帮)的人,然后给你条件说明(D)这两个编号的罪犯不是一个帮派的人,又给你一个条件(A)让你判断这两个编号的罪犯是不是一个帮派。
输入数据:
第一行:测试数据有多少组
第二行: N(罪犯的个数) M(有多少组关系和判断)
接下来的M行
A : 判断x和y在不在一个帮派,不知道关系输出Not sure yet. 不在一个帮派In different gangs. 在同一个In the same gang.
D:x和y不在同一个帮派
解题思路:
不用多想种类并查集一定是可以ac的~这题让我对种类并查集的unite和find有了更深刻的理解
初始化函数(深刻理解):
我总是喜欢用0,1,2……来区别集团是否相同是否不同,但是是以0为一个集团,1为一个集团的,现在彻底修正了,gp[i]=0是i和pa[i]是一个集团,gp[i]=1表示i和pa[i]不是一个集团的
find函数
int find(int n){
if(n!=pa[n]){
int tmp=pa[n];//先存一下原先的父节点
pa[n]=find(pa[n]);//先压缩,这样可以更好的维护树型结构
gp[n]=(gp[n]+gp[tmp])%2;//压缩后赋值
}
return pa[n];
}
对与find函数的理解,还是不会的可以自己画图模拟
uinte函数:
void unite(int x,int y){
int fx=find(x);
int fy=find(y);
pa[fy]=fx; //树可以直接把两个根节点连在一起
gp[fy]=(gp[x]+gp[y]+1)%2;
}
当计算gp[fy]的时候,这个时候两棵树的深度都是2,所以就可以分情况列出来:
1、gp[x/y]=0 的时候,根节点fy和fx不是一个帮派,为1.
2、都为1的时候,fy和fx不是一个帮派,为1,。
3,gp[x/y]其中有一个是0的情况,fy和fx是一个帮派,为0。
就可以得到gp[fy]=(gp[x]+gp[y]+1)%2;
#include<cstdio>
#include<cstring>
using namespace std;
const int max=100000+50;
int pa[max],gp[max];
void init(int n){
for(int i=1;i<=n;i++){
pa[i]=i;gp[i]=0;
}
}
int find(int n){
if(n!=pa[n]){
int tmp=pa[n];
pa[n]=find(pa[n]);
gp[n]=(gp[n]+gp[tmp])%2;
}
return pa[n];
}
void unite(int x,int y){
int fx=find(x);
int fy=find(y);
pa[fy]=fx;
gp[fy]=(gp[x]+gp[y]+1)%2;
}
int main(){
int n,a,b;
char m;
scanf("%d",&n);
while(n--){
scanf("%d%d",&a,&b);getchar();
init(a);
int x,y;
for(int j=0;j<b;j++){
scanf("%c%d%d",&m,&x,&y); getchar();
if(m=='A'&&a==2){
printf("In different gangs.\n");
continue;
}
if(m=='D')
unite(x,y);
else if(m=='A'){
if(find(x) == find(y)){
if((gp[x]+gp[y])%2) printf("In different gangs.\n");//这个是奇偶树判断,也可以用&1位运算判断x和y对根节点的关系
else printf("In the same gang.\n");
}
/* if(find(x)==find(y)){
if(gp[x]==gp[y]) printf("In the same gang.\n");
else printf("In different gangs.\n");
}*/用这个方法判断也是可以的
else printf("Not sure yet.\n");
}
}
}
return 0;
}