牛客国庆集训派对Day2 F   平衡二叉树

1 篇文章 0 订阅
1 篇文章 0 订阅

平衡二叉树

时间限制: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)];

---------------------

本文题解来自 :https://blog.csdn.net/u013852115/article/details/82927000?utm_source=copy

参考:https://blog.csdn.net/u013852115/article/details/82927000

#include <iostream>
#include <algorithm>
#include <cmath>
#include <stdio.h>
#include <queue>
#include <vector>
#include <map>
#include <cstring>
#include <set>
using namespace std;
typedef long long LL;
const int MOD=1e9+7;
LL Pow(LL a,LL b);
LL Gcd(LL a,LL b);
LL exGcd(LL a,LL b,LL &x,LL &y);
const int MAXN=1e6+7;
const int M=1e3+7;
const int MAX=0x3f3f3f3f;
LL max(LL a,LL b);
struct node
{
    int l,r;
    int val;
}tree[MAXN];
LL dp[100][100]={0};
int main()
{
   ios::sync_with_stdio(false);
    LL n,d;
    LL ans;
    while(cin>>n>>d)
    {

    memset(dp,0,sizeof(dp));
    dp[0][1]=1;
   for(int i=0;i<=d;i++)
    for(int j=1;j<=n;j++)
    {
     dp[i][j]=dp[i][j-1]+1+dp[i][max(0,j-1-i)];
    }
    if(d==0||n<=1)
        ans=0;
    else{
        d=min(d,n-1);
        ans=Pow(2,n-1)-1;
        ans-=dp[d][max(0LL,n-d-1)];
    }
    cout<<ans<<endl;
    }
    return 0;
}


LL Gcd(LL a,LL b)
{
    if(b==0)return a;
    else return Gcd(b,a%b);
}
LL Pow(LL a,LL b)
{
    LL ans=1;
    while(b!=0)
    {
        if(b&1!=0)
        {
            ans=ans*a;
        }
        a*=a;
        b>>=1;
    }
    return ans;
}

LL exGcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    LL r=exGcd(b,a%b,x,y);
    LL temp=y;
    y=x-a/b*y;
    x=temp;
    return r;
}
LL max(LL a,LL b)
{
    return a>b?a:b;
}
/*
int n,m,k,t,d;
ll dp[100];
ll val[70];
ll dfs(int x) {
    if(x<=0) return 0;
    if(dp[x]) return dp[x];
    return dp[x]=1+dfs(x-1)+dfs(x-1-d);
}
int main{
    scanf("%d%d",&n,&d);
    dp[0]=0,dp[1]=1;
    ll ans=(1LL<<(n-1))-1-dfs(n-1-d);
    printf("%lld\n",ans);
     return 0;
}

*/

 dfs——————————————

LL dp[100];
LL val[70];
int d;
LL dfs(int x)
{
    if(x<=0)return 0;
    if(dp[x])return dp[x];
    return dp[x]=1+dfs(x-1)+dfs(x-1-d);
}
int main()
{
   ios::sync_with_stdio(false);
    int n;
    cin>>n>>d;
    dp[0]=0;
    dp[1]=1;
    LL ans=Pow(2,n-1)-1;
    ans=ans-dfs(n-1-d);
    cout<<ans<<endl;

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值