转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目链接 http://poj.org/problem?id=1095
debug到蛋碎的一题,原本是熟悉下卡特兰数,结果卡特兰数部分很水,一直在调试递归
预处理卡特兰数之后,可以推出当前是多少个节点组成的二叉树,也知道是在当前节点所有排序中的名次
然后开始递归,从右子树开始枚举,判断左右子树的节点个数,递归。debug半天的原因竟然是题目没有读懂,排序关系弄错了,囧
英语不好,果然伤不起,下次读题一定要注意
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL __int64
using namespace std;
LL c[30]={1};
//预处理卡特兰数
void Init(){
for(int i=1;i<=25;i++){
c[i]=c[i-1]*(4*i-2)/(i+1);
}
}
//输出k个节点的并排在第cnt位的二叉树
void slove(int k,int cnt){
//只有一个节点,直接输出
if(k==1){
printf("X");
return;
}
//排名很靠前,只有右子树
if(cnt<=c[k-1]){
printf("X");
printf("(");
slove(k-1,cnt);
printf(")");
}
//排名很靠后,只有左子树
else if(cnt>c[k]-c[k-1]){
printf("(");
slove(k-1,cnt-(c[k]-c[k-1]));
printf(")");
printf("X");
}
else{
int t=k-1,m;
//判断左右子树各有多少个节点,更新名次
for(int i=t;i>=0;i--){
if(c[i]*c[t-i]<cnt)
cnt-=c[i]*c[t-i];
else{
m=i;
break;
}
}
printf("(");
//递归左子树
slove(t-m,cnt/c[m]+(cnt%c[m]!=0));
printf(")X(");
//递归右子树
slove(m,(cnt-1)%c[m]+1);
printf(")");
}
}
int main(){
int n,m;
Init();
while(scanf("%d",&n)!=EOF&&n){
for(int i=1;;i++){
if(n>c[i])
n-=c[i];
else{
m=i;
break;
}
}
slove(m,n);
printf("\n");
}
return 0;
}