题目链接: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记录的是每个点和它的父节点的偏移量。如果父节点是根节点,那当然就是和根节点的偏移量了,这也就是遍历到根节点的路径找到和根节点的偏移量。

附大牛详解

posted on 2010-07-14 18:09  ylfdrib  阅读(482)  评论(0编辑  收藏  举报