题目:240. 食物链 - AcWing题库
动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形。
A 吃 B,B 吃 C,C 吃 A。
现有 N个动物,以 1∼N 编号。
每个动物都是 A,B,C 中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这 N 个动物所构成的食物链关系进行描述:
第一种说法是 1 X Y
,表示 X 和 Y 是同类。
第二种说法是 2 X Y
,表示 X 吃 Y。
此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真的,有的是假的。
当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
- 当前的话与前面的某些真的话冲突,就是假话;
- 当前的话中 X或 Y 比 N 大,就是假话;
- 当前的话表示 X吃 X,就是假话。
你的任务是根据给定的 N 和 K 句话,输出假话的总数。
输入格式
第一行是两个整数 N 和 K,以一个空格分隔。
以下 K 行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中 D表示说法的种类。
若 D=1,则表示 X 和 Y 是同类。
若 D=2,则表示 X 吃 Y。
输出格式
只有一个整数,表示假话的数目。
数据范围
1≤N≤50000
0≤K≤100000
输入样例:
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
输出样例:
3
解题思路:(扩展域表示状态)
首先, 在带扩展域的并查集 中 x 不再只是一个 值,而是一个事件;
规定 x 类比为 "事件 x 为 A 类动物";
规定 x + N 类比为 "事件 x 为 B 类动物";
规定 x + N * 2 类比为 "事件 x 为 C 类动物";
q[find(X)] = find(Y) 表示
事件 X 为 A 类动物 和 事件 Y 为 A 类动物 同时发生
X 与 Y 为同种动物 等价于
q[ find(X) ] = find(Y);
q[ find(X + N)] = find(Y + N);
q[ find(X + N * 2)] = find(Y + N * 2);
状态表示 X Y动物为同类
q[find(X)] = find(Y + N) 表示
事件 X 为 A 类动物 和 事件 Y 为 B 类动物 同时发生
X 吃 Y 等价于
q[ find(X) ] = find(Y + N );
q[ find(X + N)] = find(Y + N * 2 );
q[ find(X + N * 2)] = find(Y );
状态表示 X Y动物X 吃 Y
代码献上:(扩展域表示状态--并查集)
#include<iostream>
using namespace std;
const int N = 5e4 + 10, M = N * 3;
int n, m;
int q[M];
int find(int x) //查找函数
{
return q[x] == x ? q[x] : q[x] = find(q[x]);
}
int main()
{
cin >> n >> m;
for (int i = 1; i < M; i++) q[i] = i; //初始化
int res = 0;
while (m--)
{
int d, a, b; cin >> d >> a >> b;
if (a > n || b > n) //第2条假话条件
{
res++;
continue;
}
if (a == b) //第3条假话条件
{
if (d == 2) res++;
continue;
}
if (d == 1) //同类
{
// 如果 a 吃 b 或者 b 吃 a ,则 a 与 b 是同类是假话
if (find(a) == find(b + N) || find(a + N) == find(b))
{
res++;
continue;
}
q[find(a)] = find(b); //同类化
q[find(a + N)] = find(b + N); //同类化
q[find(a + N * 2)] = find(b + N * 2); //同类化
}
else //X动物吃Y动物
{
// 如果 b 吃 a 或者 a 与 b 是同类 ,则 a 吃 b 是假话
if (find(a + N) == find(b) || find(a) == find(b))
{
res++;
continue;
}
q[find(a)] = find(b + N); //X动物吃Y动物--构建食物链
q[find(a + N)] = find(b + N * 2); //X动物吃Y动物--构建食物链
q[find(a + N * 2)] = find(b); //X动物吃Y动物--构建食物链
}
}
cout << res;
return 0;
}