带权并查集的应用,比基础模板增加了一些语句。
普通的并查集:记录的是集合是否同属一个集合。
带权并查集:记录集合的关系和着集合内元素的关系。
今天学习的一道例题是—— A Bug’s Life
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1829
题目简述:找出昆虫内是否有GAY,,,
具体步骤代码内有详解:
#include <bits/stdc++.h>
using namespace std;
//带权并查集的应用,比基础模板增加了一些语句
int pre[2001];//定义父节点
int relation[2001];//定义性别,表示x节点与根节点的关系
bool flag;
//查
int Find(int x)
{
if (x == pre[x]) return x;
int temp = pre[x];
//为路径压缩!!!
pre[x] = Find(pre[x]);//当该节点的下标与父节点不等的时候,将父节点的值付给x继续查找直到找到根节点
relation[x] = (relation[x] + relation[temp]) % 2;//更新x与父节点之间的关系,0,1表示不同性别%2判断性别
return pre[x];
}
bool join(int x,int y){
int fx=Find(x);
int fy=Find(y);
if(fx!=fy){
pre[fx]=fy;
relation[fx]=(relation[x]+relation[y]+1)%2;
return flag;
}
else{
if(relation[x]==relation[y]){//2个节点的根节点相同且以根节点为基础的两个节点的性别也相同,就是是特殊的
flag=false;
return flag;
}
}
}
int main()
{
int a,k;
k=1;
scanf("%d",&a);
while(k<=a){
flag=true;
int n,m,x,y;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){//初始化父节点的值,和关系的值
pre[i]=i;
relation[i]=0;
}
for(int i=1;i<=m;i++){
scanf("%d %d",&x,&y);
join(x,y);
}
printf("Scenario #%d:\n",k);
if(flag==false)
printf("Suspicious bugs found!\n");
else
printf("No suspicious bugs found!\n");
k++;
printf("\n");
}
return 0;
}