POJ-2492-A Bug’s Life
本题带权并查集
先开始我以为这道题跟那个龙派和蛇派的题目差不多=-=
但是后来想想不大对劲。这个题目是问你有没有错误。那个题是查询是否是同一个帮派。不对劲
题目大意:总是把题目中的bug想成代码中的bug,我真是bug脑袋=-=
实验开头结论一种稀有虫子只会吸引异性。问实验数据会不会有错或者存在同性相吸的可能
给出实验数据。
带权并查集哈
r[i]表示i与父结点的性别情况
为0表示同性。1表示异性
在find()函数和mix()函数中有关键代码
find()函数处理部分:
当前处理结点x
当发现父结点不是自己本身时。我们路径压缩过程中把根节点直接对应到了当前结点的父结点。所以relation关系要被改变
x与新父结点(根结点)的关系改为:x与原父结点的关系(就是r[x])+x原父结点与其父结点的关系(其父结点是根结点,r[fa[x]])
mod 2;
式子:r[x] = (r[x] + r[fa[x]]) % 2;
这里说x原父结点的父结点为啥是根结点?路径压缩路径压缩!
举个实际例子:x与原父结点的关系是:x为女孩子,原父结点为男孩子,即r[x] = 1,相异;
原父结点与根结点的关系:原父结点是男孩子(上面)根结点为女孩子,r[fa[x]] = 1;相异
所以x和根结点都是女孩子。当前更新:r[x] = 1;
mix()函数处理:
当x的根结点xx和y的根结点yy不一样时。我们需要合并树
这里把yy合并到xx上;
所以r[yy]需要被改变
x与xx的关系:r[x]
y与yy的关系:r[y]
(再强调一遍。路径压缩直接把x的父结点直接改为根结点了)
举一个实例:
r[x] = 1;假设x为女孩子,那xx为男孩子
r[y] = 0:假设y为女孩子,那yy为男孩子
yy合并到xx上(xx是yy的父结点)
所以我们根据数据找下关系
当前r[yy]应该更新为0(根据r[x]和r[y]找关系)
一定要mod2
相加减1就可以达到目的啦~
所以式子:
r[yy] = (r[x] + r[y] - 1 + 2) % 2;
这里加上2是为了防止负数(比如r[x]和r[y]均为0的情况)
好啦~解释完啦
最后注意格式输出
每组数据的输出用\n
代码部分:
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 2e3 + 10;
int fa[N];
int r[N];
int n, d;
int cnt;
int flag;
void init()
{
for (int i = 1; i <= n; i++)
{
fa[i] = i;
r[i] = 0;
}
}
int find(int x)
{
if (x != fa[x])
{
int xx = find(fa[x]);
r[x] = (r[x] + r[fa[x]]) % 2;
fa[x] = xx;
}
return fa[x];
}
void mix(int x, int y)
{
int xx = find(x);
int yy = find(y);
if (xx == yy)
{
if (r[x] == r[y])
{
flag = 1;
}
return ;
}
fa[yy] = xx;
r[yy] = (r[x] + 1 - r[y] + 2) % 2;
}
int main()
{
int t;
cin >> t;
while (t--)
{
flag = 0;
scanf ("%d%d", &n, &d);
init();
for (int i = 1; i <= d; i++)
{
int x, y;
scanf ("%d%d", &x, &y);
if (!flag)
{
mix(x, y);
}
}
cout << "Scenario #" << ++cnt << ":" << endl;
if (flag)
{
cout << "Suspicious bugs found!\n\n";
}
else
{
cout << "No suspicious bugs found!\n\n";
}
}
return 0;
}