zoukankan      html  css  js  c++  java
  • poj1182 食物链【并查集-好题!】

    动物王国中有三类动物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(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 
    Input
    第一行是两个整数N和K,以一个空格分隔。 
    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 
    若D=1,则表示X和Y是同类。 
    若D=2,则表示X吃Y。
    Output
    只有一个整数,表示假话的数目。
    Sample Input
    100 7
    1 101 1 
    2 1 2
    2 2 3 
    2 3 3 
    1 1 3 
    2 3 1 
    1 5 5
    
    Sample Output
    3

    最近开始练并查集了 重新回顾以前的一些专题

    懂并查集模板还是不会做的

    看了题解当做回顾一下并查集吧

    感觉这题真的挺妙的

    https://blog.csdn.net/freezhanacmore/article/details/8767413 这篇博客不错


    这题是对rank数组进行了变化,用rank来表示各个数据之间的关系

    难点是合并操作的时候他们之间的关系的更新

    其实相当于0吃1 1吃2 2吃0

    因此当他们之间的关系 0表示同类 +1表示被吃 +2表示吃

    当找x的父节点时也需要不断更新x的rank值



    合并时rank的更新



    #include <iostream>
    #include <algorithm>
    #include <stdlib.h>
    #include <cstring>
    #include <vector>
    #include <map>
    #include <set>
    #include <stdio.h>
    #include <queue>
    #include <stack>
    #define inf 0x3f3f3f3f
    
    using namespace std;
    
    const int maxn = 50005;
    int n, k;
    int parent[maxn];
    int ran[maxn];//0吃1,1吃2,2吃0
    
    void init(int n)
    {
        int i;
        for(int i = 1; i <= n; i++){
            parent[i] = i;
            ran[i] = 0;
        }
    }
    
    int fin(int x)
    {
        if(x == parent[x]) return x;
    
        int t = parent[x];
        parent[x] = fin(parent[x]);
        ran[x] = (ran[x] + ran[t]) % 3;
        return parent[x];
    }
    
    void mer(int x, int y, int d)
    {
        int tx = fin(x);
        int ty = fin(y);
        parent[tx] = ty;
        ran[tx] = (ran[y] - ran[x] + 3 + d - 1) % 3;
    }
    
    int main()
    {
        cin>>n>>k;
            int cnt = 0;
            init(n);
    
            for(int i = 0; i < k; i++){
                int d, x, y;
                scanf("%d %d %d", &d, &x, &y);
                if(x > n || y > n || (d == 2 && x == y)) cnt++;
                else{
                    int tx = fin(x);
                    int ty = fin(y);
                    if(tx == ty){
                        if((ran[x] - ran[y] + 3) % 3 != d - 1){
                            cnt++;
                        }
    
                    }
                    else{
                        mer(x, y, d);
                    }
                }
            }
    
            cout<<cnt<<endl;
    
        return 0;
    }


  • 相关阅读:
    (转)C#调用默认浏览器打开网页的几种方法
    (链接)打印相关_.NET打印小资料
    (推荐)WPF动画教程
    (转)C# 打印PDF文件使用第三方DLL
    问题解决_(转载)在VisualStudio 2012上使用MVC3出现错误的解决办法
    分布式集群
    关于集群并发问题
    关于分布式事务的处理
    分布式与集群理解之部署结构
    分布式与集群理解
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9643411.html
Copyright © 2011-2022 走看看