题目描述:
http://poj.org/problem?id=2492
中文大意:
H 教授正在研究一种稀有臭虫的性行为。
他猜测该类昆虫具有两种性别,并且是异性交配。
已知几组交配数据,判断他的猜测是否存在 bug。
思路:
我们规定:若 i 属于集合 A ,则 i+n 属于集合 B。
两种性别可以抽象为两个集合,x 和 y 是两只交配的昆虫。
若 x 和 y 属于不同的集合,则 x 和 y+n 属于同一集合,y 和 x+n 属于同一集合;
若 x 和 y 属于相同的集合,则说明 H 教授的猜测存在 bug。
代码:
#include<iostream>
using namespace std;
int n,m;
int sets[4002];//各节点的所属集
int height[4002];//各集合的树高
//初始化,各节点分别属于独立的集合
void init(int n){
for(int i=1;i<=n;i++){
sets[i] = i;
height[i] = 1;
}
}
//寻找节点 x 的所属集
int find(int x){
//寻找根节点
int root = x;
while(root != sets[root]){
root = sets[root];
}
//路径压缩:将路径上节点的所属集修改为根节点
int i = x;
while(sets[i] != root){
int j = sets[i];
sets[i] = root;
i = j;
}
return root;
}
//合并
void union_set(int x, int y){
//寻找节点 x 的所属集
x = find(x);
//寻找节点 y 的所属集
y = find(y);
//若两个节点的所属集树高相同,则将 x 的所属集并到 y 的所属集
if(height[x] == height[y]){
sets[x] = y;
height[y]++;
}//否则,将矮树并到高树,且高树的树高保持不变
else if(height[x] > height[y]){
sets[y] = x;
}
else{
sets[x] = y;
}
}
int main(){
int t;
scanf("%d", &t);
for(int k=1;k<=t;k++){
//存在空行
if(k != 1){
printf("
");
}
scanf("%d %d", &n, &m);
init(2*n);
bool have_bug = false;//是否有 bug
int x,y;
for(int i=0;i<m;i++){
scanf("%d %d", &x, &y);
//若节点 x 和节点 y 属于不同集合
if(find(x) != find(y)){
//规定:如果节点 i 属于集合 A,则 i+n 属于集合 B
union_set(x, y+n);
union_set(y, x+n);
}
else{
have_bug = true;
}
}
printf("Scenario #%d:
", k);
if(have_bug){
printf("Suspicious bugs found!
");
}
else{
printf("No suspicious bugs found!
");
}
}
}