题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=62
首先之前如果有卡特兰数的概念的话,这道题会比较好理解一点,首先了解如果有N个节点,组成的二叉树有多少种? 这是等价于有N个数的出入栈序列有多少种,都等于Catalan[n]
所以输入要的第N序号的树的时候,要先找到这个序号所在的树有多少个节点,然后要知道在这些节点组成的树中是第几棵,这些要利用CATALAN数来求,也就是main里的作用。
output ( int x, int n) : N是这颗树有多少个节点,X是要的树在N个节点组成的树中的序号。
知道了这两个信息之后,我们枚举左右子树的节点个数, i 表示左子树的个数,j表示右子树的个数,然后递归。
#include <cstdio>
using namespace std;
int num[20] = {1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012,
742900, 2674440, 9694845, 35357670, 129644790, 477638700};
void output(int x,int n)
{
if ( n==0 )
return ;
if ( n==1 )
{
printf("X");
return;
}
int i=0,j=n-1;
int left;
for(i=0;i<n;i++,j--)
{
left=num[i]*num[j];
if ( x>left )
x-=left;
else
break;
}
x--;
if ( i!=0 )
{
printf("(");
output((x/num[j])+1,i);
printf(")");
}
printf("X");
if (j!=0)
{
printf("(");
output((x%num[j])+1,j);
printf(")");
}
}
int main()
{
int n;
int s[20];
s[0]=0;
s[1]=1;
for(int i=2;i<=19;i++)
{
int cat=0;
int k=i-1;
for(int j=0;j<i;j++,k--)
{
cat+=num[j]*num[k];
}
num[i]=cat;
s[i]=s[i-1]+num[i];
}
while(scanf("%d",&n)&&n!=0)
{
int i=1;
for(i=1;i<=19;i++)
{
if ( s[i]>=n)
{
break;
}
}
output(n-s[i-1],i);
printf("\n");
}
}