AC情况:
思路:种类并查集。
这个题目只需要输入一组,可以写的简单一点,但是第一次做这种题目,我想加深点印象所以把函数都完整的写了一下,以后回顾也方便。
因为一共有3种动物,且是循环的吃的关系,一般情况下不能确定谁是第一种谁是第二种第三种,所以把每个动物i都分成3个元素:i-A、i-B、i-C。如果输入说法1 x y,则说明x-A=y-A、x-B=y-B、x-C=y-C。如果输入说法2 x y,则说明x-A=y-B、x-B=y-C、x-C=y-A。定义i代表i-A,i+n代表i-B,i+2n代表i-C。
#include<iostream>
using namespace std;
const int MAX_N = 50001;
int par[3*MAX_N],ran[3*MAX_N];
int i;
//初始化函数
void init(int n) {
for (i = 0; i < n; i++) {
par[i] = i;
ran[i] = 0;
}
}
//找元素x的父节点
int find(int x) {
int k, j, r;
r = x;
while (r != par[r])r = par[r];
k = x;
while (k != r) {
j = par[k];
par[k] = r;
k = j;
}
return r;
}
//合并元素x和y
void unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y)return;
if (ran[x] < ran[y]) {
par[x] = y;
}
else {
par[y] = x;
if (ran[x] = ran[y]) ran[x]++;
}
}
//检验x和y的父节点是否相同
bool same(int x, int y) {
return find(x) == find(y);
}
int main() {
int n, k;
cin >> n >> k;
int t, x, y;
init(n * 3);
int ans = 0;
for (i = 0; i < k; i++) {
cin >> t >> x >> y;
x--; //把输入元素的范围调整为0~n-1,因为要根据par[x]寻找父节点,par是从0存的
y--;
if (x >=n || y >= n) {
ans++;
continue;
}
if (t == 1) {
if (same(x, y + n) || same(x, y + 2 * n)) {
ans++;
}
else {
unite(x, y);
unite(x + n, y + n);
unite(x + 2*n, y +2* n);
}
}
else {
if (same(x, y) || same(x, y + 2 * n)) {
ans++;
}
else {
unite(x, y+n);
unite(x + n, y + 2*n);
unite(x + 2 * n, y );
}
}
}
cout << ans<<endl;
return 0;
}