带权并查集
这题只有两种关系,所以比食物链简单一点
两种关系:
0:a,b 同性
1:a,b 异性
当a与b并到一起时,a与b肯定互为异性
而union函数是将a的父节点连到b节点上
所以
1、当a与父节点同性时,父节点与b互为异性
2、当a与父节点互为异性时,父节点与b同性
不难得出关系更新方程:
rlt[A] = (rlt[a] + rlt[b] + 1) % 2;// A is the father of a
判断a,b间关系是否和谐:
若a,b不在同一棵树上则和谐
在同一棵树上时:
1、a,b与父节点(通过状态压缩为同一父节点)的关系相同,则不和谐
2、a,b与父节点的关系不相同,则和谐
代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define N 2333
using namespace std;
int n,f[N];
int rlt[N];
int find (int x)
{
if (f[x] == x)
return x;
int tmp = f[x]; // important !
f[x] = find (f[x]);
rlt[x] = (rlt[x] + rlt[tmp]) %2;
return f[x];
}
void Union (int a,int b)
{
int A = find (a);
int B = find (b);
if (A != B)
{
f[A] = B;
rlt[A] = (rlt[a] + rlt[b] + 1) % 2;
}
}
bool check (int a,int b)
{
int A = find(a);
int B = find(b);
if (A != B)
return true;
return (rlt[a] != rlt[b]);
}
int main ()
{
int T,m,a,b,c;
scanf ("%d",&T);
for (int t=1;t<=T;t++)
{
scanf ("%d%d",&n,&m);
for (int i=0;i<=n;i++)
{
f[i] = i;
rlt[i] = 0;
}
bool flag = false;
for (int i=1;i<=m;i++)
{
scanf ("%d%d",&a,&b);
if (check(a,b))
Union (a,b);
else
flag = true;
/*for (int i=1;i<=n;i++)
cout<<i<<" : "<<f[i]<<" "<<rlt[i]<<endl;cout<<endl;*/
}
printf ("Scenario #%d:\n",t);
if (flag)
printf ("Suspicious bugs found!\n\n");
else
printf ("No suspicious bugs found!\n\n");
}
return 0;
}