AcWing 240. 食物链

食物链

240. 食物链 - AcWing题库

视频讲解:AcWing 240. 食物链 (算法基础课) - AcWing

大佬对find函数的详细解读:AcWing 240. 食物链—数组d的真正含义以及find()函数调用过程 - AcWing

这道题目对于算法初学者来说,真的好难好难…

即使在y总的帮助下我找到了用并查集这个比较好的解题思路,还是举步维艰

这篇感觉是大佬的话,应该很快也能AC,但是如果是非大佬的话,没有思路,多少文字讲解都没有,建议去AcWing上看y总视频讲解,对他的解题思路很详细的进行了讲解,然后也还可以再看看底下的评论,是对很多边界情况的思维风暴,同时也利于我们加深对这种解法的理解和提高自己的思维能力,思维周密程度

我的能力就只能是我自己理解好y总的代码,把代码尽可能用通俗语言注释好,做到每一步我们最少都能看懂是在干什么

建议解不出这题的同学们可以花时间看一遍y总的视频讲解,受益匪浅的,然后再自己尝试代码实现,然后可以对照对照我的注释去看看

#include<iostream>
using namespace std;
int n,m;
const int N = 50010;
int p[N],d[N];

int find(int x)
{
    if(p[x]!=x)
    {
        //find一直递归到最后会返回这个集合的根节点,我们用temp把他存下来
        int temp = find(p[x]);
        d[x]+=d[p[x]];//回溯的时候,让d[x]变成x到它所在集合祖宗节点的距离
        p[x] = temp;//路径压缩 回溯过程中把每个节点x的p[x]都修改成根节点
    }
    //由于14行已经修改成根节点,所以我们find函数的返回值就是根节点
    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;
        scanf("%d%d%d",&t,&x,&y);
        //规则2
        if(x>n||y>n)res++;
        else
        {   
            //找出x和y的所在集合根节点
            int px = find(x),py = find(y);
            if(t == 1)//同类语句
            {
                //px == py表示x和y在同一个集合中
                //(d[x]-d[y])%3如果不为0,说明他们不属于同一级,则这是假话
                if(px == py&&(d[x]-d[y])%3)res++;
                else if(px!=py)//表示x和y之前就没在一个集合中
                {
                    //既然没在,那么我们就建立集合 这里默认是把x所在集合并在y的集合中,同时py作为根节点
                    p[px] = py;
                    //这一步的推导 建议大家用纸模拟
                    d[px] = d[y] - d[x];
                }
            }
            else //t = 2,x吃y语句
            {
                //(d[x]-d[y]-1)%3等于0的话 表示d[x]模3比d[y]模3要大一 也即满足x吃y
                if(px == py&&(d[x]-d[y]-1)%3)res++;
                else if(px!=py)
                {
                    //同样还是集合合并
                    p[px] = py;
                    //这一步同样也是建议纸上模拟
                    d[px] = d[y]-d[x]+1;
                }
            }
        }
    }
    cout<<res<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值