【acwing】240. 食物链

题目

在这里插入图片描述

思路一

在这里插入图片描述
如何将不同并查集合并,对于同类(1)来说:
在这里插入图片描述
对于不同类(2)来说:
在这里插入图片描述

代码1

#include<iostream>
using namespace std;

const int N=50005;
int p[N],d[N];
int n,m;

int find(int x){//记录到根节点的距离
    if(p[x]!=x){
        int t=find(p[x]);  
        d[x]+=d[p[x]];
        p[x]=t;
    }
    return p[x];
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        p[i]=i;  //所有的父节点都是自己
    }
    
    int res=0;
    while(m--){
        int t,x,y;
        cin>>t>>x>>y;
        if(x>n || y>n){   //x,y大于n的范围,这句话是假话
            res++;
        }else{
            int px=find(x);//x的根节点
            int py=find(y);//y的根节点
            
            if(t==1){//x和y是同类
                if(px==py && (d[x]-d[y])%3!=0){  //在同一棵树上,两个点的距离差%3不为0,说明不是同类
                    res++;
                }else if(px != py){ //x,y不在同一颗树上
                    p[px]=py;  //x的根节点连在y的根节点上
                    d[px]=d[y]-d[x];
                }
            }else{//x吃y
                if(px==py && (d[x]-d[y]-1)%3!=0){ //x,y在同一颗树上,x的距离比y大一,即(dx-dy-1)%3==0
                    res++; 
                }else if(px != py){//x,y不在同一颗树上,
                    p[px]=py;//x的根节点连在y的根节点上
                    d[px]=d[y]+1-d[x];
                }
            }
        }
    }
    
    cout<<res<<endl;
    return 0;
}

思路二

并查集(拓展域)
这道题目我们主要是要开三个拓展的域,也就是天敌域,同类域,以及捕食域.

如果x,y是同类,但是x的捕食域有y,那么❎
如果x,y是同类,但是x的天敌域有y,那么❎
如果x,y是同类,但是x的同类域有y,那么✅

如果x是y的天敌,但是x的同类域中有y,那么❎
如果x是y的天敌,但是x的天敌域中有y,那么❎
如果x是y的天地,但是x的捕食域中有y,那么✅

我们让当前X的捕食域为X+N,当前X的天敌域为X+N+N

代码2

//我们让当前X的捕食域为X+N,当前X的天敌域为X+N+N
#include<iostream>
using namespace std;

const int N=50000*3+5;

int p[N];
int n,m;

int find(int x){
    if(x!=p[x]){
        p[x]=find(p[x]);
    }
    return p[x];
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=3*n;i++){
        p[i]=i;
    }
    
    int res=0;
    while (m -- ){
        int k,x,y;
        cin>>k>>x>>y;
        if(x>n || y>n){
            res++;
        }else if(k==1){//x和y同类
            if(find(x)==find(y+n) || find(x)==find(y+n+n)){//x在y的捕食域中,x在y的天敌域中
                res++;
            }else{
                p[find(x)]=p[find(y)];  //x和y同类
                p[find(x+n)]=p[find(y+n)];  //x的捕食域和y的捕食域同类
                p[find(x+n+n)]=p[find(y+n+n)];  //x的天敌域和y的天敌域同类
            }
        }else{  //x是y的天敌
            if(x==y || find(x)==find(y) || find(x)==find(y+n)){ //x和y是同一个,x和y是同类,x是y的捕食域
                res++;
            }else{
                p[find(x)]=p[find(y+n+n)]; //y的天敌域中加入x
                p[find(x+n)]=p[find(y)];  //x的捕食域中加入y
                p[find(x+n+n)]=p[find(y+n)];  //x的天敌域和y的捕食域是同类
            }
        }
    }
    cout<<res<<endl;
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值