poj2492 A Bug’s Life
题目大意:输入互相交配的两只虫,检查是否存在同性恋情况…
对于此题,二分图染色较为局限不适用此题,拆点并查集要创建相对立的节点不适合此题,此题适合用种类并查集,边权存储两边节点是否为同一性别,是同一性别为1,不是同一性别为0,路径压缩时要注意维护更新。
解题思路:
将发生关系的两只虫聚合——能连接在一起的就不是一个性别的虫
对于两只虫,比较一下看发生过关系没,有同一个根节点就代表之前发生了关系,根节点不同就是之前没发生过关系;再看看这两只虫的性别,如果这两只虫发生过关系并且性别相同,即导出矛盾。
#include <bits/stdc++.h>
using namespace std;
int pre[20010];
int r[20010];//记录性别,r=0代表同性
int Find(int x) { //路径压缩,许多结点的父结点会改变,需要根据实际情况调整权值以保证其正确性 模板!
if(pre[x]==x) return x; //x的父亲是x, 表示找到根节点了,返回根节点
int t;
t=pre[x]; //将x的父亲保存下
pre[x]=Find(pre[x]); //压缩路径,把x的父亲变成x父亲的父亲。。。
r[x]=(r[x]+r[t]+1)%2; //异或运算,维护节点x和父亲的关系,r[x]==0时和父亲同类,==1时和父亲异类
return pre[x]; //x的父亲
}
void Union(int a, int b) {
int x,y;
x=Find(a); y=Find(b); //将a、b的父亲找出来
pre[x]=y; //让x认y做父亲
r[x]=(r[b]-r[a])%2; //更新x与父亲的关系:a和b本来不一个集合,祖先也就不同,r的值是1,现在让他们相同,即让他们的值异或一下
}
int main() {
int t, i, j, k, flag;
int n, m, a, b;
scanf("%d",&t); //场景数
for(k = 1; k <= t; k++) {
flag=0;
scanf("%d%d",&n,&m); //全部的虫子数量 观察到的交配次数
for(i=1; i<=n; i++) {
r[i]=1;
pre[i]=i; //初始化,先认自己做父
}
for(i=1; i<=m; i++) {
scanf("%d%d",&a,&b); //交配的两只虫子
if(Find(a)==Find(b)) { //根节点相同,a和b原来发生过关系---ab异性
if(r[a]==r[b]) { //同性
flag=1; //矛盾
}
}
else Union(a,b); //ab原来没有关系,就将a的集合和b的集合合并
}
if(flag) printf("Scenario #%d:\nSuspicious bugs found!\n\n",k);
else printf("Scenario #%d:\nNo suspicious bugs found!\n\n",k);
}
return 0;
}
find函数用来路径压缩,Union函数为合并集合,均为模板