1. 程式人生 > >牛客國慶集訓派對Day2 F 平衡二叉樹【遞推】

牛客國慶集訓派對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;
}