食物链

题目连接: 食物链

大致题意:

有三种动物, 共有N个, 组成A->B->C->A的食物链关系, 有k个说法, 让你判断其中的假话.

假话: ①前面的真话冲突 ②动物编号超过N ③同类吃同类

解题思路:

并查集. 维护集合中节点到根节点的距离(%3计算).

假设某种动物是0(根节点), 则吃他的生物为1, 被他吃的生物为2, 同类则也为0. (距离%3后的结果)
我们在进行判断的时候, 一定是判断当前这个生物与他所在集合中根节点的情况, 所以找查函数中, 我们必须要对每个节点进行路径压缩, 并且将非根父节点的距离增加到当前节点上.

我们可以得到结果, 如果x与y在一个集合内, 且到根节点距离相同 ==> x与y同种生物. 如果到根节点距离差1 ==> y吃x, 如果差2 ==> x吃y

AC代码:

#include 
typedef long long ll;
using namespace std;
const int N = 5E4 + 10;
int p[N], d[N];
int find(int x) {
	if (p[x] == x) return x; 
	int temp = p[x]; //当前节点不是根节点, 进行路径压缩以及维护d数组操作
	p[x] = find(p[x]); //这里p[x]其实返回的是根节点, 所以上面要用temp临时存储p[x]
	d[x] += d[temp]; //这样d[x]就增加的是当前这个节点到他原本上个父节点的距离
	return p[x];
}
int main(void)
{
	int n, k; scanf("%d %d", &n, &k);
	for (int i = 1; i <= n; ++i) p[i] = i; //并查集初始化

	int t, x, y; int res = 0;
	while (k--) {
		scanf("%d %d %d", &t, &x, &y);
		if (x > n || y > n) { res++; continue; } //不符合2, 至于3和1可以合并判断
		int px = find(x), py = find(y); //得到x与y的根节点
		if (t == 1) {
			if (px == py && (d[x] - d[y]) % 3) res++; //在一个集合, 且不是同类
			else if (px != py) { //不在一个集合, 则建立关系
				p[px] = py;
				d[px] = d[y] - d[x]; //要满足 d[x] + X == d[y]
			}
		}
		else {
			if (px == py && (d[x] - d[y] - 1) % 3) res++; //在一个集合, x不是被y吃
			else if (px != py) { //不在一个集合, 建立关系
				p[px] = py;
				d[px] = d[y] + 1 - d[x]; //要满足 d[x] - d[y] + X == 1
			}
		}
	}
	printf("%d\n", res);
	return 0;
}

END

你可能感兴趣的:(并查集,思维题目,算法,acm,icpc,并查集,数据结构)