Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
问题描述
思路
我们可以从例子入手来寻找规律。
如图所示,对于例子的这棵树,我们发现无论怎么调整第二层2、3、4的顺序,他们肯定都会为二叉树贡献3个深度。 唯一不同的就是,如果把2结点放在最底下,那么由于2有儿子,因此会令二叉树额外向下伸一格。如果把二放在上面的任意一层,都不会对二叉树的深度有贡献。最好的选择就是把‘2’结点放在了兄弟的最后一位。
那么,一般来说最好的选择是什么?
我们发现对于任意一颗树A,我们要求他变成二叉树后的最大深度。它的根结点连着若干个子节点,可以看作若干个子树。每个子树可以递归的求他们变成二叉树能达到的最大深度,然后选出深度最高的,把他放在兄弟结点的最后一位,这样A树就也可以达到最大深度。A的深度即为子节点(子树)的个数加上所有子树中最大能达到的深度。
这道题看上去用递归做很直观,但是题目有个条件,那就是“每个父节点的编号比自己的编号小”。这就意味着如果我们从大到小遍历节点来求最大深度,可以不用递归,直接就能自底向上一步到位。具体看代码即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=100000+5;
vector<int> sons[maxn];
int dp[maxn];
int main(){
int n;
cin>>n;
for(int i=2;i<=n;i++){
int father;
cin>>father;
sons[father].push_back(i);
}
for(int i=n;i>=1;i--){
//先找儿子
dp[i]=sons[i].size();
int mx=0;
for(int j=0;j<sons[i].size();j++){
int son=sons[i][j];
mx=max(dp[son],mx);
}
dp[i]+=mx;
}
cout<<dp[1];
return 0;
}
总结
有时候就是要大胆寻找全局最优,很有可能大力出奇迹。