题目链接: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"); } }