【备战蓝桥杯】7.左孩子右兄弟——贪心

625 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

问题描述

下载.png

下载.png

思路

我们可以从例子入手来寻找规律。

如图所示,对于例子的这棵树,我们发现无论怎么调整第二层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;
}

总结

有时候就是要大胆寻找全局最优,很有可能大力出奇迹。