题目链接:[POJ 2492]A Bug's Life[并查集]
题意分析:
给出n个虫子,和m个虫子间的关系a,b,代表a喜欢b。问:在给出的关系中,是否存在同性恋的虫子呢?
解题思路:
和基础的并查集不同,这里判断a、b间的关系需要利用到之前已有的信息判断。这里我们设置a-b+n代表a虫和b虫是不同的性别,如果存在a-b是属于相同的集合,那么就是同性恋存在。因为根据我们所设的集合,a如果会与b属于同一集合,那么必定是a、b同时爱上另外一只虫子才会这样。
个人感受:
网上还有一种方法是:用一个数组记录每个虫子性别相反的虫子,然后每次合并性别相同的虫子。虽然也是好理解,不过移植到其它题我个人就觉得不是很好用了,比如POJ 1703。所以我还是选了这个比较通用的记下。
具体代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN = 4e3 + 111;
int p[MAXN], ran[MAXN];
void init(int up)
{
for (int i = 0; i <= up; ++i) p[i] = i, ran[i] = 0;
}
int find(int x)
{
return p[x] == x ? x : p[x] = find(p[x]);
}
void unite(int x, int y)
{
x = find(x), y = find(y);
if (x == y) return;
if (ran[x] > ran[y]) p[y] = x;
else
{
p[x] = y;
if (ran[x] == ran[y]) ++ran[x];
}
}
int main()
{
int t, n, m, a, b; scanf("%d", &t);
for (int kase = 1; kase <= t; ++kase)
{
bool flag = 0;
scanf("%d%d", &n, &m);
init(2 * n);
for (int i = 0; i < m; ++i)
{
scanf("%d%d", &a, &b);
if (find(a) == find(b)) flag = 1;
else
{
unite(a, b + n);
unite(a + n, b);
}
}
printf("Scenario #%d:\n", kase);
if (flag) printf("Suspicious bugs found!\n\n");
else printf("No suspicious bugs found!\n\n");
}
}