洛谷 1814

来源:互联网 发布:闲鱼淘宝介入多久 编辑:程序博客网 时间:2024/06/16 09:12
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;}



0 0
原创粉丝点击