时隔一段时间没写题解,这一次抽空刷了一道有关于树形dp的题目,有讲的不好的地方请多多指教,如果有哪个地方没讲清楚欢迎在评论区留言。
题目链接:P8744 [蓝桥杯 2021 省 A] 左孩子右兄弟 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目大意:给定一个树,请问采用”左孩子右兄弟“ 法构造出来的高度最长有多长?
首先要理解题目中的所谓左孩子右兄弟法是什么,这是一种多叉树转化为二叉树的一种方法,一颗多叉树用这种方法可以构造出多种二叉树,下图将展示一种方式来讲解:
我用红线和蓝线区别出所连结点的变化可以发现,2号结点的兄弟结点3,4号结点变为他的孩子结点,这正是多叉树转化为二叉树的方式,由此可以总结:与某一结点父亲结点相同的兄弟结点变为他的孩子结点。
由上面可以得出,我们只需要将所有高度最高的结点与其兄弟结点相连就可以得到高度最高的结点,因此我们可以用高度height记录某一结点之下高度最高的结点,用表示以i为根结点的最大高度,再最后加上i结点之下的直接结点的数量(即最高的结点的兄弟结点),由根结点向上递归即可,还有由于是高度所以要在结果-1。
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
using namespace std;
using ll=long long ;
using pii=pair<int,int> ;
#define endl "\n"
constexpr int N=2e5+10;
constexpr int mod=1e9+7;
int a[N],dp[N];
int h[N],e[N],nex[N],idx;
void add(int a,int b)
{
e[idx]=b,nex[idx]=h[a],h[a]=idx++;
}
void dfs(int u)
{
dp[u]=1;
int height=0;
for(int i=h[u];i!=-1;i=nex[i])
{
int v=e[i];
dfs(v);
dp[u]++;
height=max(height,dp[v]);
}
if(height)height--;
dp[u]+=height;
}
void solve()
{
int n;
cin>>n;
memset(h,-1,sizeof h);
for(int i=2;i<=n;i++)
{
int father;
cin>>father;
add(father,i);
}
dfs(1);
cout<<dp[1]-1<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
t=1;
while(t--)
solve();
return 0;
}