食物链------种类并查集

本文介绍使用并查集解决POJ 1182问题的方法,通过定义特殊数组记录节点间关系,实现对食物链中物种关系的判断。文章详细解释了关键代码逻辑及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题传送门 :http://poj.org/problem?id=1182



推荐blog传送门,超级详细:http://blog.youkuaiyun.com/c0de4fun/article/details/7318642/



这种题,渣渣我是刚不了的……,百度了一堆帖子,说实话谈到关键代码的真的不是很多,也确实有好的帖子,让我收获了不少。

做题思路:

种类并查集,首先利用一个数组a来确定并查集关系,同时在建立一个数组b来表示某点与他们的boss点(根点)的关系。

现规定:

0: 某点与他的根点为同类

1: 某点与他的根点的关系为, 根点种类的动物的可以吃掉该点种类的动物

2: 某点与他的根点的关系为, 该点种类的动物的可以吃掉根点种类的动物

至于 那两个重要公式(代码已标注),如果自己不想推就去看推荐的那个blog,很详细。



几点注意:

1.如果两点没有并查集关系,首先给他们确定并查集关系

2. 如果两点有了并查集关系,检验他们所陈述的与根点的关系是否相同

3. 注意 输入的数据大于n的时候 不要让他们进入mergy函数



代码如下

#include <iostream>
#include<cstdio>
#include<cstring>
#include <algorithm>
using namespace std;
int ans;
int a[50100];
int b[50100];
void Init ()//初始化两个数组
{
    for(int i=1; i<=50100; i++)
    {
        a[i]=i;
        b[i]=0;
    }
}
int get_boss(int x)
{
    if(a[x]==x) return x;
    else
    {
        int t=a[x];
        a[x]=get_boss(a[x]);
        b[x]=(b[x]+b[t])%3;//带权并查集式,重要公式1
        return a[x];
    }
}

void mergy(int z,int x, int y)
{
    int t1=get_boss(x);
    int t2=get_boss(y);
    if(z==1)
    {
        if(t1==t2)
        {
            if(b[x] != b[y])//false
                ans++;
        }
        else
        {
            a[t2]=t1;
            b[t2] = (b[x]-b[y]+3+(z-1))%3;//重要公式2, 另外+3的原因式剪发可能出现负数,因为模3,,3无所谓
        }
    }
    else
    {
        if(t1==t2)
        {
            if( (b[x]+1) %3 !=b[y] ) // false // 下述推导
            //(b[x]==0 && b[y]==1) || (b[x]==1 && b[y]==2) || (b[x]==2 && b[y]==0),除了这三种都是错的语句
             ans++;
        }
        else
        {
            a[t2]=t1;
            b[t2] = (b[x]-b[y]+3+(z-1))%3;
        }
    }
}
int main ()
{
    int n,m,x,y,z;
    scanf("%d %d",&n,&m);
    Init();
    ans=0;
    while(m--)
    {
        scanf("%d %d %d",&z,&x,&y);
        if(x>n|| y>n) ans++; //false
        else if(x==y && z==2) ans++; // false
        else  mergy(z,x,y);// n<x, n<y 千万不要让他们进来,错了N遍 
    }
    printf("%d\n",ans);
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值