题目
51nod上的一道题,求节点数为n(n<=2000)的不同形态的AVL树有多少种,结果对10^9+7取模。
解法
设dp[i][j]是节点数为i,高度为j的AVL树的数量,则树的左右子树的高度只有3种可能,分别是(j-1,j-1),(j-1,j-2),(j-2,j-1),所以枚举x为左子树的节点数,y为右子树的节点数,h为左子树的节点数,dp[i][j]+=dp[h][x]*dp[i-h-1][y];
代码
#include<cstdio>
#define LL long long
#define mod 1000000007
LL dp[2005][20];
int mi[20],ma[20],dir[5][2]={-1,-1,-1,-2,-2,-1};
int main()
{
int n,i,j,k,h;
//ma[i]是高度为i的AVL树的最大节点数
ma[1]=1;
for(i=2;i<=20;i++)
ma[i]=ma[i-1]*2+1;
//mi[i]是高度为i的AVL树的最小节点数
mi[1]=1;mi[2]=2;
for(i=3;i<=20;i++)
mi[i]=mi[i-1]+mi[i-2]+1;
dp[1][1]=1;dp[2][2]=2;
for(i=3;i<=2000;i++)
for(j=1;j<=20;j++)
{
if(i<mi[j]||i>ma[j])
continue;
for(k=0;k<3;k++)
{
int x=j+dir[k][0];
int y=j+dir[k][1];
for(h=mi[x];h<=ma[x];h++)
{
if(i-h-1>=1&&mi[y]<=i-h-1&&ma[y]>=i-h-1)
dp[i][j]=(dp[i][j]+dp[h][x]*dp[i-h-1][y]%mod)%mod;
}
}
}
while(~scanf("%d",&n))
{
LL ans=0;
for(i=1;i<=20;i++)
ans=(ans+dp[n][i])%mod;
printf("%lld\n",ans);
}
return 0;
}