POJ1182 食物链 并查集
Posted wtyuan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ1182 食物链 并查集相关的知识,希望对你有一定的参考价值。
POJ1182
题目
有三类动物A、B、C,三类动物的食物链构成环形,A吃B,B吃C,C吃A。给定N个动物,编号1到N(1<=B<=50000),每个动物都是A、B、C的一种。按顺序给出如下的两种信息共K(0<=K<=100000)条。
- x和y属于同一类
- x吃y
然而这些信息可能出错,出错的原因有如下三种:
- 当前的信息与前面的某些真的信息冲突,就是假的信息
- 当前的信息中,x与y比N大
- 当前的话表示x吃x
统计出假的信息的数量。
Sample Input
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
Sample Output
3
算法思路
第2、3类错误原因很容易处理,重点是如何处理第1类错误原因,当处理当前信息时,我们需要知道当前信息是否与之前的真的信息有冲突。假如当前信息表明,x与y是同类,则我们需要判断之前的真的信息中,是否有信息表明x与y不同类(即x吃y,或y吃x),假如当前信息表明x吃y,我们需要判断之前的真的信息中,是否有信息表明x与y同类或y吃x。那么如何实现上述操作呢?每来一个信息,我们只知道x与y的关系,而不知道x、y分别属于哪一个类,而每一种关系都可以对应三种情况。若x与y同类,则x和y为A,为B,为C都可以。若x吃y,则x为A,y为B,x为B,y为C,x为C,y为A这三种情况都可以。那如何处理呢?答案是三种情况均考虑到。
参考《挑战程序设计竞赛》(第2版)中的思路,采用特殊的并查集来解决这个问题对于每只动物i创建三个元素i-A,i-B,i-C(分别表示i属于A、B、C),并用这(3 imes N)个元素建立并查集。对于每一条信息,进行如下操作:
- 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,同样把上文中的三种情况都考虑到了。
以上合并操作使得,每一个组内的所有元素代表的情况都同时发生,例如若i-A和j-B在同一组内,则说明i属于A,j属于B是同时发生的。不过在合并之前,需要确定是否与之前的真的信息产生矛盾:
- x和y属于同一类,则需要判断之前是否有真的信息表明x吃y或y吃x。即x-A、y-B是否是同一组或y-A、x-B是否是同一组。
- x吃y,则需要判断之前是否有真的信息表明x与y同类或y吃x,即x-A、y-A是否是同一组或y-A、x-B是否是同一组。
由于合并操作每次把三种情况都考虑到了,所以判断时只需要对一种情况判断即可。
代码
Result: 1196kB, 297ms
#include <stdio.h>
#include <iostream>
#define N 50000
int n, k;
int parent[3 * N + 10];
void MakeSet() {
for (int i = 1; i <= 3 * N; i++)
parent[i] = i;
}
int Find(int x) {//路径压缩
while (x != parent[x])
x = parent[x];
return x;
}
void Union(int x, int y) {
int r = Find(x), s = Find(y);
if (r == s)
return;
else
parent[r] = s;
}
int main() {
scanf("%d %d", &n, &k);
int d, x, y, cnt = 0;
MakeSet();
while (k--) {
scanf("%d %d %d", &d, &x, &y);
if (x > n || y > n)//第二种信息
cnt++;
else if (d == 2 && x == y)//第三种信息
cnt++;
else {//第一种信息
if (d == 1) {//x与y同类
if (Find(x) == Find(y + n) || Find(y) == Find(x + n))//不允许之前的真的信息表明x吃y或y吃x
cnt++;
else {
Union(x, y);
Union(x + n, y + n);
Union(x + 2 * n, y + 2 * n);
}
}
else {//d = 2,x吃y
if (Find(x) == Find(y) || Find(y) == Find(x + n))//不允许之前的真的信息中表明x与y同类或y吃x
cnt++;
else {
Union(x, y + n);
Union(x + n, y + 2 * n);
Union(x + 2 * n, y);
}
}
}
}
printf("%d
", cnt);
system("pause");
return 0;
}
```
参考:
[1] 《挑战程序设计竞赛》(第2版)
以上是关于POJ1182 食物链 并查集的主要内容,如果未能解决你的问题,请参考以下文章
带权并查集(含种类并查集)经典模板 例题:①POJ 1182 食物链(经典)②HDU - 1829 A bug's life(简单) ③hihoCoder 1515 : 分数调查(示例代码(代