洛谷 1814

1.我们可以用一个简单的dp算出用i个节点组成二叉树的方案数,令f[i]表示用i个节点组成二叉树的方案数,则f[i]=Σ(f[j]*f[i-1-j]), 因为我们考虑选1个点为根,枚举左子树的节点数,然后根据乘法原理计算。

2.我们可以设计一个递归函数打印答案,不难想到具体的框架是【打印左子树-->打印X-->打印右子树】,然后这样递归做下去,令get_tree(m,s)表示打印用m个节点,组成序号为s的二叉树,这里的序号的意思是用正好m个节点构成的二叉树的排名。

3.我们怎么在递归函数中得知其左右子树需要的节点数和排名呢?我们可以先算出用m个节点,其中i个节点用于左子树,构成排名小于s的i的最大值, 令那个小于s的个数称为now,此时的i+1的值称为pos,那么s-now即为多出的排名数,pos为此时左节点数(因为当左节点数为i时排名小于s,因此左节点数必为i+1,即pos),  右子树排名最大值是f[m-1-pos],因此我们需要用多出的排名先尽量填右子树,右子树填满后再将其清空增加左子树,即L=(s-now-1)/f[m-1-pos]+1,R=(s-now-1)%f[m-1-pos]+1。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[50],n;

void get_tree(int m,int s)
{
	int now=0,pos;
	if (m==1) 
	{
		printf("X");
		return;	
	}
	for (int i=0;i<m;i++) 
	{
		now+=(f[i]*f[m-1-i]);	
		pos=i;
		if (now>=s) break;
	}
	now-=(f[pos]*f[m-1-pos]);
	int L=(s-now-1)/f[m-1-pos]+1;
	int R=(s-now-1)%f[m-1-pos]+1;
	if (pos!=0) 
	{
		printf("(");
		get_tree(pos,L);
		printf(")");	
	}
	printf("X");
	if (m-1-pos!=0) 
	{
		printf("(");
		get_tree(m-1-pos,R);
		printf(")");
	}
	return;
}

int main()
{
	f[0]=f[1]=1;
	for (int i=2;i<=20;i++) 
		for (int j=0;j<i;j++) f[i]+=f[j]*f[i-1-j];
	while (scanf("%d",&n)==1) 
	{
		if (n==0) break;
		int sum=0,ord;
		for (int i=1;sum<n;i++) 
		{
			sum+=f[i];
			ord=i;
		}
		sum=n;
		for (int i=1;i<ord;i++) sum-=f[i];
		get_tree(ord,sum);	
		printf("\n");	
	}
	return 0;	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值