题目链接:[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"); } }