• [NOI2001]食物链


     洛谷原题链接

    这是一道分类并查集的题目。

    我们要根据题目的要求,求出谎话的数目。题目给了我们一些明确的判断标准:

    但是我们会发现,如果只按照这三个条件和普通的并查集,我们只能得30分。

    30分做法:我们可以用普通并查集和一个表示谁是谁的食物的数组来完成。

    30分代码:

    #include<bits/stdc++.h>
    #define R register int
    #define M 500500
    using namespace std;
    int n,k,fa[M],ans,eat[M];
    inline int find(int x){return fa[x]= fa[x]==x ? x : find(fa[x]);}
    int main(){
        ios::sync_with_stdio(0);
        int q,x,y;
        cin>>n>>k;
        for(R i=1;i<=n;++i) fa[i]=i;
        for(R i=1;i<=k;++i){
            cin>>q>>x>>y;
            if(x>n || y>n)    ++ans;
            else if(q==1){
                if(eat[x]==y || eat[y]==x) ++ans;
                else if(find(x)!=find(y)) fa[find(x)]=find(y);
            }
            else{
                if(x==y || eat[y]==x || find(x)==find(y) || eat[x]!=0) ++ans;
                else eat[x]=y;
            }
        }
        printf("%d",ans);
        return 0;
    }

    满分做法:

    当我们再次仔细读题,就会发现,题目中是有几条隐含在题意里面的判断条件的。

    从这里我们可以看出一共只有3种动物,而且食物链是一个环。那么我们就可以得出这样一条关系:如果x的食物是y,那么y的天敌是x,x的天敌是y的食物。这样的话很显然,一个数组是无法完成判断的。而且我们并不知道,x和y分别是哪一种动物。

    这时候我们就可以用种类并查集来实现这道题。种类并查集可以用来处理维护一些对立的关系,比如:敌人的敌人是朋友。我们通常会把并查集数组扩大n倍,n就是种类。所以这道题我们就可以开三倍的并查集数组,1到n表示种类A,n+1到n*2表示种类B,n*2+1到n*3表示种类C。然后我们就可以在合并的过程中维护各个点的信息了。

    还有部分解释在写在代码注释里了哦↓ ↓ ↓ ↓ ↓ ↓ ↓

    满分代码:

    #include<bits/stdc++.h>
    #define R register int
    #define M 500500
    using namespace std;
    int n,k,fa[M],ans; //n表示同类  n+n表示食物  n+n+n表示天敌 
    inline int find(int x){return fa[x]= fa[x]==x ? x : find(fa[x]);}
    inline void unity(int x,int y){fa[find(x)]=find(y);} 
    int main(){
        ios::sync_with_stdio(0);
        int q,x,y;
        cin>>n>>k;
        for(R i=1;i<=n*3;++i) fa[i]=i;
        for(R i=1;i<=k;++i){
            cin>>q>>x>>y;
            if(x>n || y>n)    ++ans;
            else if(q==1){
                if(find(x+n)==find(y) || find(x+(n<<1))==find(y)) ++ans;
                //判断x是y的同类是假话:y是x的食物 , y是x的天敌 
                else unity(x,y),unity(x+n,y+n),unity(x+(n<<1),y+(n<<1));
                //如果x和y是同一个种类:那么x和y是同一种类,x和y的食物是同一种类,x和y的天敌是同一种类 
            }
            else{
                if(x==y || find(x)==find(y) || find(x)==find(y+n)) ++ans;
                //判断x吃y是假话:x能吃x(题目要求),x和y是同类的,x是y的食物 
                else unity(x,y+(n<<1)),unity(x+n,y),unity(x+(n<<1),y+n);
                //如果x吃y:y的天敌是x,y是x的食物,x的天敌是y的食物(因为一共只有三种动物,而且食物链是一个环形的,不理解的看一下代码后面的图片) 
            }
        }
        printf("%d",ans);
        return 0;
    }

  • 相关阅读:
    Java-IO流系列-随机存取文件流
    Java-IO流系列-标准输入输出流
    Java-IO流系列-转换流
    Java-IO流系列-缓冲流
    Java-IO流系列-FileInputStream和FileOutStream
    Java-IO流系列-FileReader与FileWriter
    Java-IO流系列-IO流原理以及流的分类
    windows使用chrome调试ios webView
    页面上多个audio只播放一个
    阿里网盘分享
  • 原文地址:https://www.cnblogs.com/Glacier-elk/p/9774918.html
Copyright © 2020-2023  润新知