• P2024 [NOI2001]食物链(洛谷)


      题目传送门

      核心解法(并查集):

        关键要理清楚这些关系是怎样的:即通过了解题意可知:假设现在有如下三种动物类型:老虎,老虎的食物,老虎的天敌。所输入的x y都只满足这三种类型(输入m次去判断关系),x y是两个独立的未知种类的动物(即不知道是老虎本体、食物还是天敌)。现在需要通过构建且查询个体间的关系,因此我们需要使用并查集,只不过并查集从维护两者间的关系到维护三者间的关系。并且并查集的模板仍然适用,可以直接套,只不过初始化时元素个数由n变为3n。原因如下:以前只需要判断是否为同一组即可所以设置为n,但是此处有本体、食物、天敌这三个组别,不只是判断为是否来自一组的问题。
        为了便于存放, 一倍存本身,二倍存食物,三倍存天敌;但我们需要注意:天敌可以吃本身,食物是吃天敌的。

    实现代码:

     1 #include<bits/stdc++.h>
     2 #include <cstring>
     3 using namespace std;
     4 
     5 #define MAX_N 500005
     6 int n,m,k;
     7 int rank[MAX_N];            //树的高度 
     8 int par[MAX_N]; 
     9 int ans=0;                    //记录假话数量
    10 int T[MAX_N],X[MAX_N],Y[MAX_N]; 
    11 void init(){
    12     for(int i=1;i<=3*n;i++){
    13         par[i]=i;
    14         rank[i]=0;
    15     }
    16 }
    17 
    18 int find(int x){        //查询树的根 
    19     if(par[x]==x){
    20         return x;
    21     }else return par[x]=find(par[x]);        //在查找的过程中实际上直接将父节点连接到根节点上进行优化 
    22 }
    23 
    24 void unite(int x,int y){
    25     x=find(x);
    26     y=find(y);
    27     
    28     if(x==y)    return;
    29     
    30     if(rank[x]<rank[y]){
    31         par[x]=y;
    32     }else{
    33         par[y]=x;
    34         if(rank[x]==rank[y])    rank[x]++;        //两棵树一样高时,合并在x树上后X的高度加1 
    35     }
    36 }
    37 
    38 bool same(int x,int y){
    39     return find(x)==find(y);
    40 } 
    41 
    42 int main(){
    43     cin>>n>>m;
    44     for(int i=1;i<=m;i++){
    45         cin>>T[i]>>X[i]>>Y[i];
    46     }
    47     init();
    48     
    49     for(int i=1;i<=m;i++){
    50         int t=T[i],x=X[i],y=Y[i];
    51         
    52         if(x<1||x>n||y<1||y>n){    //先判断边界(满足条件2)
    53             ans++; 
    54             continue;        //跳过去看下一句话 
    55         }
    56         
    57         if(t==1){            //表示x  y同类时 
    58             if(same(x,y+n)||same(x,y+2*n)){//如果x是y的猎物或者x是y的天敌(则代表x y这两只动物不同类),显然是谎言( 
    59                 ans++;
    60                 continue;
    61             }else{                //下面都从老虎的视角(本体)来看 
    62                 unite(x,y);        //本体和本体是一个类型的,所以要合并 
    63                 unite(x+n,y+n);    //食物和食物是一个类型的(即x的食物也是y的食物)
    64                 unite(x+2*n,y+2*n);     //天敌和天敌是一个类型的 (即x的天敌也是y的天敌) 
    65             }
    66         }else if(t==2){        //表示x吃掉y(即y是x的食物关系)时 
    67             if(x==y){        //若x==y表示是同一个动物,没必要写但可以稍微加快速度 
    68                 ans++;
    69                 continue;
    70             }
    71             if(same(x,y)||same(x+2*n,y)){    //表示动物x和动物y是同类型的(都假设是本体来看)或者y是x的天敌(即y吃x),表明这是谎言 
    72                 ans++;
    73                 continue;
    74             }else{
    75                 unite(x+n,y);            // x的食物与y同类型 
    76                 unite(x+2*n,y+n);        //x的天敌与y的食物同类型 
    77                 unite(x,y+2*n);                //x与y的天敌同类型 
    78             }
    79         }
    80     }
    81     cout<<ans;
    82     return 0;
    83 }
  • 相关阅读:
    Django同步数据库(/manage.py makemigrations) 报错
    python中global和nonlocal用法的详细说明
    linux系统下载pycharm
    第一次博客作业
    结对编程作业
    团队介绍与选题报告
    FTP的时间为什么比系统时间晚了八个小时?
    新的部落格
    Enter键提交表单
    Android动画RotateAnimation(fromDegrees, toDegrees, pivotX,pivotY)参数
  • 原文地址:https://www.cnblogs.com/xwh-blogs/p/12608176.html
Copyright © 2020-2023  润新知