POJ 1095 Trees Made to Order(卡特兰数+递归)

Description
定义二叉树的编号:
1.空树编号0
2.只有一个节点的树编号为1
3.有m+1个节点的树编号比所有有m个节点的树的编号大
4.对节点数相同的的树,右子树节点数多的树编号小,右子树节点数相同则递归右子树,同样是右子树节点多的树编号小
先给出一个编号n,输出这课二叉树
Input
多组输入,每组用例为一个整数n表示一棵二叉树的编号,以n=0结束输入
Output
对于每组用例,输出这课二叉树,用X表示一个节点,每一对括号表示一棵树,以 (左子树)X(右子树) 的形式输出这棵树,当然如果是空树就不输出
Sample Input
1
20
31117532
0
Sample Output
X
((X)X(X))X
(X(X(((X(X))X(X))X(X))))X(((X((X)X((X)X)))X)X)
Solution
以num[i]表示有i个节点的二叉树数量,则有num[i]=num[0]num[i-1]+num[1]*num[i-2]+…+num[i-2]*num[1]+num[i-1]*num[0],这是卡特兰数的定义之一,所以我们预处理出卡特兰数即可得到有i个节点的二叉树数量(这个可以换个公式用ktl[i]=ktl[i-1](4*i-2)/(i+1)来处理),那么对于每个n,我们首先推出这棵树有多少个节点,然后判断这棵树左右子树是否非空来分三种情况进行递归输出即可
Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
#define maxn 33
ll ktl[maxn];
void init()//预处理卡特兰数 
{
    ktl[0]=1;
    for(int i=1;i<maxn;i++)ktl[i]=ktl[i-1]*(4*i-2)/(i+1);
}
void order(int n,int m)//递归输出有m个节点的二叉树中的n棵树 
{
    if(m==1)//只有一个节点则输出X即可 
    {
        printf("X");
        return ;
    }
    if(n<=ktl[m-1])//左子树为空树 
    {
        printf("X(");
        order(n,m-1);
        printf(")");
    }
    else if(n>ktl[m]-ktl[m-1])//右子树为空树 
    {
        printf("(");
        order(n-(ktl[m]-ktl[m-1]),m-1);
        printf(")X");
    }
    else//左右子树均非空 
    {
        int pos;
        for(int i=m-1;i>=1;i--)//推出右子树的节点数 
            if(n>ktl[i]*ktl[m-1-i])n-=ktl[i]*ktl[m-1-i];
            else{pos=i;break;}
        printf("(");
        order(n/ktl[pos]+(n%ktl[pos]!=0),m-1-pos);//递归左子树 
        printf(")X(");
        order((n-1)%ktl[pos]+1,pos);//递归右子树 
        printf(")");
    }
}
int main()
{
    init();
    int n;
    while(~scanf("%d",&n),n)
    {
        for(int i=1;i<maxn;i++)//推出这棵树的节点数 
            if(n>ktl[i])n-=ktl[i];
            else{order(n,i);break;}
        printf("\n");
    }
    return 0;
}

你可能感兴趣的:(POJ 1095 Trees Made to Order(卡特兰数+递归))