POj 2492 关系异或
加权并查集
- 无法确定bug具体是男还是女,只能知道他们是
同性
还是异性
- 都合并到一个数中,通过边的权值来记录是
同性
还是异性
- 开一个数组
rala[]
记录点i
与点i
的父亲节点的关系,1
代表性别不同,0
代表性别相同 - 给出的2点肯定是异性,先判2点断根节点是否一样,相同就通过2点分别推根节点的性别是否一样,一样就正好已经在树中,不一样则不满足教授推论
- 根节点不一样就合并根节点,(按照性别关系来合并)
#include <iostream>
#include <string.h>
using namespace std;
const int maxn = 2e4;
int n,m;
int a,b;
int pre[maxn];
int rala[maxn];
void init(int k) {
memset(rala,0,sizeof rala);
for (int i=1; i<=k; i++) pre[i] = i;
}
int find(int x) {
int temp = pre[x];
if (x==pre[x]) return x;
pre[x] = find(temp);
rala[x] = rala[x]^rala[temp];
return pre[x];
}
void merge(int a,int b) {
int ra = find(a);
int rb = find(b);
if (ra == rb) return;
pre[ra] = rb; // 按规定的顺序来写rala
rala[ra] = (rala[a] + rala[b] +1)%2;
}
int cnt;
int main() {
// freopen("a.txt","r",stdin);
int scenery ;
scanf("%d",&scenery);
while (scenery--) {
scanf("%d%d",&n,&m);
init(n); //并查集初始化
bool flag = true;
for (int i=1; i<=m; i++) {
scanf("%d%d",&a,&b);
// 先判断有没有错误
int ra = find(a);
int rb = find(b);
if (ra == rb) {
if (rala[a]^rala[b] != 1)
flag = false; //这里不退出的原因是 要把该组的所有的输入都读取完
}
else { // 根不相同 分别加入到自己的阵营
merge(a,b); // 通过find已经使得a,b指向各自根节点,现在判断关系,符合关系则合并根节点.
}
}
if (flag)
printf("Scenario #%d:\nNo suspicious bugs found!\n",++cnt);
else {
printf("Scenario #%d:\nSuspicious bugs found!\n",++cnt);
}
if (scenery != 0) printf("\n");
}
return 0;
}