zoukankan      html  css  js  c++  java
  • AcWing:240. 食物链(扩展域并查集 or 带边权并查集)

    动物王国中有三类动物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句话有的是真的,有的是假的。

    当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

    1) 当前的话与前面的某些真的话冲突,就是假话;
    2) 当前的话中X或Y比N大,就是假话;
    3) 当前的话表示X吃X,就是假话。

    你的任务是根据给定的N和K句话,输出假话的总数。

    输入格式

    第一行是两个整数N和K,以一个空格分隔。

    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。

    若D=1,则表示X和Y是同类。

    若D=2,则表示X吃Y。

    输出格式

    只有一个整数,表示假话的数目。

    数据范围

    1N500001≤N≤50000,
    0K1000000≤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

    题解:

    扩展域并查集:我们把每个动物拆成3个节点,分别是同类域xself,捕食域xeat,天敌域xenemy。

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    const int maxn = 3e5+7;
    
    int f[maxn];
    
    int get(int x) {
        if(x == f[x]) {
            return f[x];
        }
        int root = get(f[x]);
        return f[x] = root;
    }
    
    int main() {
        int n, m;
        scanf("%d %d", &n, &m);
        for(int i = 1; i <= 3 * n; i++) {
            f[i] = i;
        }
        int ans = 0;
        while(m--) {
            int op, x, y;
            scanf("%d %d %d", &op, &x, &y);
            int x_self = x, x_eat = x + n, x_enemy = x + n + n;
            int y_self = y, y_eat = y + n, y_enemy = y + n + n;
            if(x > n || y > n) {    //动物编号不存在
                ans++;
            } else if(op == 1) {    //x和y是同类关系
                if(get(x_eat) == get(y_self) || get(x_self) == get(y_eat)) {    //如果x捕食的物种和y的同类在同一集合,或者x的同类和y捕食的物种在同一集合,那么不成立,此话是假
                    ans++;
                } else {    //合并同类物种
                    f[get(x_self)] = get(y_self);
                    f[get(x_eat)] = get(y_eat);
                    f[get(x_enemy)] = get(y_enemy);
                }
            } else {    //x和y是捕食关系,x吃y
                if(get(x_self) == get(y_self) || get(x_self) == get(y_eat)) {    //如果x的同类和y的同类在同一集合,或者x的同类和y捕食的物种在同一集合,那么不成立,此话是假
                    ans++;
                } else {    //合并同类物种
                    f[get(x_eat)] = get(y_self);
                    f[get(x_self)] = get(y_enemy);
                    f[get(x_enemy)] = get(y_eat);
                }
            }
        }
        printf("%d
    ", ans);
        return 0;
    }

    带边权并查集:

    看这篇优秀的博客,里面解释的很清楚:https://blog.csdn.net/linkfqy/article/details/69055713

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    const int maxn = 5e4+7;
    
    int f[maxn];
    int d[maxn];
    
    int get(int x) {
        if(x == f[x]) {
            return f[x];
        }
        int root = get(f[x]);
        d[x] += d[f[x]];
        return f[x] = root;
    }
    
    int main() {
        int n, m;
        scanf("%d %d", &n, &m);
        int ans = 0;
        for(int i = 0; i <= n; i++) {
            f[i] = i;
            d[i] = 0;
        }
        while(m--) {
            int x, y, w;
            scanf("%d %d %d", &w, &x, &y);
            if(x > n || y > n || (w == 2 && x == y)) {
                ans++;
                continue;
            }
            int fx = get(x);
            int fy = get(y);
            if(fx == fy) {
                if(((d[x] - d[y]) % 3 + 3) % 3 != w - 1) {
                    ans++;
                }
            } else {
                f[fx] = f[fy];
                d[fx] = d[y] + (w - 1) - d[x];
            }
        }
        printf("%d
    ", ans);
        return 0;
    }
  • 相关阅读:
    Linux下Git远程仓库的使用详解
    Git单人本地仓库操作
    分布式版本控制系统之Git
    搭建Redis集群
    搭建 Redis 的主从
    Redis与Python进行交互
    Redis的数据类型以及各类型的操作
    Redis服务端和客户端的命令
    配置Redis
    Linux下Redis的安装
  • 原文地址:https://www.cnblogs.com/buhuiflydepig/p/11396963.html
Copyright © 2011-2022 走看看