食物链
视频讲解: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;
}