http://poj.org/problem?id=1182
对于每只动物 i 创建3个元素,i-A, i-B, i-C,并用3 x N 个元素建立并查集,这个并查集维护如下信息:
# i - x 表示 i 属于种类i;
# 并查集里的每一组表示组内所有元素代表的情况都同时发生或不发生。
第一种 x 和 y属于同种类, 合并 x-A和y-A, x-B和y-B, x-C和y-C;
第二种 x 吃 y 合并x-A和y-B,x-B和y-C, x-C和y-A;
代码
#include <stdio.h> #include <stdlib.h> #include <string> #include <string.h> #include <map> using namespace std; #define MAX_N 50001*3 #define MAX_K 100005 int par[MAX_N], t[MAX_K], a[MAX_K], b[MAX_K], n, k; void init() { for (int i = 0; i <= n * 3; i++) { par[i] = i; } } int find(int x) { int y = x; while (y != par[y]) { y = par[y]; } while (x != par[x]) { int px = par[x]; par[x] = y; x = px; } return y; } void Union(int x, int y) { int ra = find(x), rb = find(y); par[ra] = rb; } void slove() { int sum = 0, z, x, y; for (int i = 0; i < k; i++) { z = t[i]; x = a[i]; y = b[i]; if (x < 1 || x > n || y < 1 || y > n) { sum++; continue; } if (z == 1) { //x, y属于同一类 if (find(x) == find(y + n) || find(x) == find(y + 2 * n)) { sum++; continue; } else { Union(x, y); Union(x + n, y + n); Union(x + 2 * n, y + 2 * n); } } else { //想吃y if (find(x) == find(y) || find(x) == find(y + 2 * n)) { sum++; continue; } else { Union(x, y + n); Union(x + n, y + 2 * n); Union(x + 2 * n, y); } } } printf("%d\n", sum); return; } int main() { //freopen("1.in","r",stdin); int i; scanf("%d %d",&n,&k); init(); for (i = 0; i < k; i++) { scanf("%d %d %d", &t[i], &a[i], &b[i]); } slove(); system("pause"); return 0; }