题目链接:http://poj.org/problem?id=1703
题目大意:两组犯罪团体,抓住N个人,他们属于且唯一属于两组犯罪团体之一。然后,给你M条信息,也分两类。D类信息说明id0和id1是不同组织的,A类信息是询问id0和id1的关系,包括不同组织,相同组织和无法判断。
解题思路:
并查集,但简单并查集思路与该题目不符合。因为简单并查集会告诉你两个目标是相同组织的,此题恰好相反。但是,两人属于不同组织说明他们是有联系的,也就是说1D2, 2D3,那么1和3的关系是可以推断出来的,也就可以将1,2,3理解为一个集合(暂且叫做不等集合,里面包含许多不等关系,这些不等关系可以推出相等关系)。
那么D信息表明id0所属的集合与id1所属的集合应该是同一个不等集合的(合并)。然而,在并查集中,不等集合都需要一个根作为代表。这里谁做根都可以,但是必须让根的父节点等于根,C2G[x]=x。 这里可能会有疑问:不是不等集合吗?那么C2G[i]和i的关系到是什么?
C2G[i] 表示i的根,但是在不等集合里是无法确定C2G[i]与i的组织关系。因此,另外用rank记录i,rank[i]表示i和C2G[i]的组织关系,0代表相同,1代表不同。
#include<stdio.h>
const int MAX_N = 100001;
int C2G[MAX_N];
int Rank[MAX_N];
int T, N, M;
void init(){
for(int i = 1; i <= N; i++){
C2G[i] = i;
Rank[i] = 0;
}
return;
}
int Find(int x){
if( x == C2G[x] ){
Rank[x] = 0;
return x;
}
int fx = Find(C2G[x]);
Rank[x] = (Rank[x] + Rank[C2G[x]]) % 2;
C2G[x] = fx;
return C2G[x];
}
void Union(int x, int y){
int fx = Find(x);
int fy = Find(y);
if( fx == fy ){
return ;
}
else{
C2G[fx] = fy;
Rank[fx] = (Rank[x] + Rank[y] + 1) % 2;
}
return;
}
int main(){
scanf("%d", &T);
for(int i = 0; i < T; i++){
scanf("%d%d", &N, &M);
init();
char str;
int id0, id1;
for(int j = 0; j < M; j++){
scanf("\n%c%d%d", &str, &id0, &id1);
if( str == 'A' ){
int FatherId0 = Find(id0);
int FatherId1 = Find(id1);
if( FatherId0 == FatherId1 ){
if( Rank[id0] == Rank[id1] ){
printf("In the same gang.\n");
}
else{
printf("In different gangs.\n");
}
}
else{
printf("Not sure yet.\n");
}
}
else{
Union(id0, id1);
}
}
}
return 0;
}