ZOJ1062

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


 

你可能感兴趣的:(ZOJ1062)