题意:一群臭虫的脑残生活,告诉你臭虫之间的交配关系,问里面是否有gay或les。
用并查集来做
Set数组保存集合或父亲节点,Rel数组保存该元素与父亲节点的关系。
每告诉你一对关系,先判断是否在同一集合中,如果不在,则合并两个元素所在的集合,若在同一个集合中,则判断两者是否有不正当的关系。
关系的相互转化:运用到离散数学中二元关系方面的知识 a-c=a-b ^ b-c 例如:a-b的关系是1,b-c的关系是1,则a-c的关系是0
关系的转化在两个情况下进行,1.并查集的路径压缩优化时进行转化。2.合并两个集合时,确定两个集合的关系时需要转化。
合并时因为已经进行了路径压缩,则有A-B = A-a ^ a-b ^ b-B 由于关系^可逆 所有A-a = a-A
#include<stdio.h>
int Set[2001],Rel[2001];
int Case,N,M,Flag,TT;
int Find(int a){
int root;
if(Set[a]!=a){
root=Find(Set[a]);
Rel[a]=Rel[a]^Rel[Set[a]];
Set[a]=root;
return root;
}
return a;
}
void UnionSet(int a,int b){
int A,B;
A=Find(a);
B=Find(b);
if(A!=B){
Set[A]=B;
Rel[A]=Rel[a]^1^Rel[b];
}
}
void Judge(int a,int b){
if(Rel[a]==Rel[b])
Flag=1;
}
int main(){
int i,a,b,A,B;
scanf("%d",&Case);
TT=1;
while(TT<=Case){
Flag=0;
memset(Rel,0,sizeof(Rel));
scanf("%d %d",&N,&M);
for(i=1;i<=N;i++)
Set[i]=i;
for(i=1;i<=M;i++){
scanf("%d %d",&a,&b);
if(Flag) continue;
A=Find(a);
B=Find(b);
if(A!=B)
UnionSet(a,b);
else
Judge(a,b);
}
printf("Scenario #%d:\n",TT);
if(Flag)
printf("Suspicious bugs found!\n\n");
else
printf("No suspicious bugs found!\n\n");
TT++;
}
return 0;
}