题目链接:A Bug's Life
分析:很经典的一道并查集,这题关键在如何维护每一个点到集合顶点的偏移量。第一次了解偏移量,还是挺有收获的!对于两个点x,y,分别找到他们的根节点fx,fy。(fx = find(x); fy = find(y);)如果fx == fy 则找到一对同性恋者,return,否者:bin[fx] = fy; fx指向fy,为了保证x和y为异性,即相对根节点的偏移量不同,fx的偏移量offset[fx] = (offset[x] + offset[y] + 1); 是同或关系,这样只对根节点操作,就不影响其它各点间的相互关系。还有:在路径压缩的过程中,采用递归形式,由根节点反向改变每个叶子节点的值,这样只用比较当前节点和他父节点之间的关系了:offset[r] = (offset[r] + offset[bin[r]]) % 2;是异或关系。
代码
#include<stdio.h>
#include<stdlib.h>
#define NN 2005
int bin[NN];
int offset[NN];
int ok;
int find(int x){
int r = x;
if (bin[r] == r){
return r;
}
int t = find(bin[r]);
offset[r] = (offset[r] + offset[bin[r]]) % 2;
bin[r] = t;
return bin[r];
}
void merge(int x, int y){
int fx, fy;
fx = find(x);
fy = find(y);
if (fx == fy){
if (offset[x] == offset[y]){
ok = 1;
return ;
}
}else{
bin[fx] = fy;
offset[fx] = (offset[x] + offset[y] + 1) % 2;
}
}
int main()
{
int n, sce, i, nbug, nint, a, b;
scanf("%d", &n);
for (sce = 1; sce <= n; sce++){
scanf("%d%d", &nbug, &nint);
for (i = 1; i <= nbug; i++){
bin[i] = i;
offset[i] = 0;
}
ok = 0;
while (nint--){
scanf("%d%d", &a, &b);
merge(a, b);
}
printf("Scenario #%d:\n", sce);
if (ok) puts("Suspicious bugs found!");
else puts("No suspicious bugs found!");
puts("");
}
return 0;
}
这种用递归形式压缩路径的方法还是第一次写,学习了!正是因为是递归形式,才能实现由根节点层层反向改变的要求。其中offset记录的是每个点和它的父节点的偏移量。如果父节点是根节点,那当然就是和根节点的偏移量了,这也就是遍历到根节点的路径找到和根节点的偏移量。