洛谷 P2024 食物链(并查集)

版权声明: https://blog.csdn.net/yczhaoxun/article/details/79967513

题目链接: https://www.luogu.org/problemnew/show/P2024

题意:有三种生物A,B,C,它们的关系是A吃B,B吃C,C吃A。现在给出一些语句,判断是否是假话,输出假话数量。

输入类似 a x y,如果a等于1,说明x,y是同类,a等于2说明x是y的天敌。

思路:经典的并查集题目,用x表示生物本身,x+n表示它的猎物,x+2*n表示它的敌人,具
体请看代码注释。

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
const int maxn = 5e4+2;//生物数量,分为三类:A,B,C

int N, K, ans = 0;;//K是语句数量,ans是假话数量
int fa[3 * maxn];

int read(){//快读
    int x=0;
    char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    return x;
}

int find(int x){//并查集查询操作
    if(x == fa[x]) return fa[x];
    return fa[x] = find(fa[x]);
}
int unity(int x, int y){//合并操作
    int a = find(fa[x]),b = find(fa[y]);
    fa[a] = b;
}
int main(){
    N = read(); K = read();
    for(int i = 1; i <= 3 * N; i++)//这里是3*N
        fa[i] = i;//初始化
    for(int i = 1; i <= K; i++){
        int a, x, y;
        a = read(); x = read(); y = read();
        if(x > N || y > N){//不在范围类,当然是假话
            ans++;
            continue;
        }
        if(a == 1){//如果x,y是同类
            if(find(x + N) == find(y) || find(x + 2*N) == find(y)){
                ans++;//如果x的猎物是y或者x的天敌是y,肯定不行
                continue;
            }
            unity(x, y);//二者是同类
            unity(x + N, y + N);//猎物相同
            unity(x + 2*N, y + 2*N);//天敌相同
        } 
        else if(a == 2){//如果x的猎物是y
            if(x == y){//不能相等,可有可无吧
                ans++;
                continue;
            }
            if(find(x + 2*N) == find(y) || find(y) == find(x)){
                ans++;//y不能是x的天敌和同类
                continue;
            }
            unity(x, y + 2*N);//x是y的天敌
            unity(x + N, y);//x的猎物是y
            unity(x + 2*N, y + N);//根据A吃B,B吃C,C吃A,x的天敌是y的猎物
        }
    }
    printf("%d\n",ans);//输出
return 0;
}

总结:并查集用于处理集合的合并问题真是太强大了。

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页