POJ 1095

#include <iostream>
#define MAXN 20
using namespace std;
__int64 cat[MAXN];
int sum;
void give_catalan();
void dfs(int node,int num);
int main()
{
    //freopen("acm.acm","r",stdin);
    give_catalan();
    int n;
    int i;
    int sum;
    while(cin>>n,n)
    {
        sum = 0;
        for(i = 1; sum < n; ++ i)
        {
            sum += cat[i];
        }
        -- i;
        sum -= cat[i];
        dfs(i,n-sum);
        cout<<endl;
    }
}

void dfs(int node,int num)
{
    if(node == 1)
    {
        cout<<'X';
        return;
    }
    int i;
    int j;
    int sum = 0;
    for(i = 0; sum < num; ++i)
    {
        sum += cat[i]*cat[node-i-1];
    }
    -- i;
    sum -= cat[i]*cat[node-i-1];
    num -= sum;
    if(i > 0)
    {
        cout<<"(";
        dfs(i,(num-1)/cat[node-i-1]+1);
        cout<<")";
    }
    cout<<'X';
    if(node-1-i > 0)
    {
        cout<<"(";
        dfs(node-1-i,(num-1)% cat[node-i-1]+1);
        cout<<")";
    }
}
void give_catalan()
{
    int i;
    int j;
    cat[0] = 1;
    cat[1] = 1;
    for(i = 2; i < 20; ++ i)
    {
        cat[i] = 2*(2*(i-1)+1)*cat[i-1]/(i+1);
    //    printf("%d
",cat[i]);
    }
}
/*
定理:n个结点能形成的二叉树总数为 卡特兰数 C(2n,n)/(n+1) 或者由递推公式Ci+1=2*(2*i+1) /(i+2)*Ci 
  for(i=2;i<20;i++) 
    {        
        a[i]=2*(2*(i-1)+1)*a[i-1]/(i+1) ;//卡特兰数递推公式
        b[i]=b[i-1]+a[i];   
    }   
    
  (2).继续转化问题,这棵树的左子树和右子树各有结点数多少?设这棵树左子树的结点数为i,右子树的结点数为n-i-1,
  那么这棵树是又左子树的结点数为i,右子树的结点数为n-i-1的形态的第几种(设为第s种)?可以知道当1<=k<=L[0]*L[n-1]时,
  左子树结点树为0,右子树结点数为n-1,s=k;L[0]*L[n-1]+1<=k<=L[1]*L[n-2]时,,左子树结点树为1,
  右子树结点数为n-2,s=k- L[0]*L[n-1] ;...当L[i-1]*L[n-i]+1<= L[i]*L[n-i+1]时,左子树结点树为i,
  右子树结点数为n-i-1,            。

(3).继续想象s增长的过程即为树形态不断发生变化的过程。那么首先是右子树在发生变化,从1到L[n-i-1]。
继续增长,右子树的形态复位为1,而左子树的形态增加1.因此右子树相当于秒针,左子树相当于分针。
对于s,该树的左子树编号为(s-1)/L[n-i-1]+1,右子树编号为(s-1)% L[n-i-1]+1。

(4).fun(n,k)的递归终止条件很容易知道,为n==1。此时树的形态只有一种,所以直接打印X。
*/

关注我的公众号,当然,如果你对Java, Scala, Python等技术经验,以及编程日记,感兴趣的话。 

技术网站地址: vmfor.com

原文地址:https://www.cnblogs.com/gavinsp/p/4563275.html