牛客国庆集训派对Day2 F 平衡二叉树【递推】
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 1048576K,其他语言2097152K
64bit IO Format: %lld
题目描述
平衡二叉树,顾名思义就是一棵“平衡”的二叉树。在这道题中,“平衡”的定义为,对于树中任意一个节点,都满足左右子树的高度差不超过 d. 空树的高度定义为0,单个节点的高度为1,其他情况下树的高度定义为根节点左右子树高度最大值 + 1. 一棵在高度上平衡的树,节点数可能不平衡,因此再定义一棵树的不平衡度为这棵树中所有节点的左右子树的节点数之差的最大值。
给定平衡的定义参数d, 你需要求出所有高度为 n 的平衡树中不平衡度的最大值。
输入描述:
两个整数,n, d.
输出描述:
一个整数:所有高度为 n 的平衡树中不平衡度的最大值。
示例1
输入
4 1
输出
5
说明
下面这棵树在 d=1 的定义下高度是平衡的,其不平衡度为 5。
备注:
0 ≤ n, d ≤ 60
思路:
子树的最大结点数很容易求出来,就是一棵满二叉树。
对于满足平衡度的子树的最少节点数,我们可以用分治的思想来求。
定义dp[i][j]表示平衡因子为i时,总共有j层的平衡树的最少节点。
我们可以算出这个树的左子树的深度为j-1,右子树的深度为max(0,j-1-d)。而这些信息前面已经计算过了。
这样就可以得出转移方程:dis[i][j]=dis[i][j-1]+1+dis[i][max(0,j-1-i)];
代码:
#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define MAXN 1005
ll n,d,dis[70][70];
int main()
{
scanf("%lld%lld",&n,&d);
memset(dis,0,sizeof dis);
dis[0][1]=1;
for(int i=0;i<=d;i++)//平衡因子
{
for(int j=1;j<=n;j++)//层数
{
dis[i][j]=dis[i][j-1]+1+dis[i][max(0,j-1-i)];
}
}
if(n<=1 || d==0) printf("0\n");
else
{
d=min(d,n-1);
ll lch=(1LL<<(n-1))-1;
printf("%lld\n",lch-dis[d][max(0LL,n-1-d)]);
}
return 0;
}