pku OJ 的第1095题,有关卡特兰数与二叉树的括号表示。
Description
The empty tree is numbered 0.
The single-node tree is numbered 1.
All binary trees having m nodes have numbers less than all those having m+1 nodes.
Any binary tree having m nodes with left and right subtrees L and R is numbered n such that all trees having m nodes numbered > n have either Left subtrees numbered higher than L, or A left subtree = L and a right subtree numbered higher than R.
The first 10 binary trees and tree number 20 in this sequence are shown below:
![](https://i-blog.csdnimg.cn/blog_migrate/862ab7d4c5583093781b5715502a9ec3.gif)
Your job for this problem is to output a binary tree when given its order number.
Input
Output
A tree with no children should be output as X.
A tree with left and right subtrees L and R should be output as (L')X(R'), where L' and R' are the representations of L and R.
If L is empty, just output X(R').
If R is empty, just output (L')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)
将所有二叉树按上图中示例编号:
1.空树编号为0,只有一个节点的树编号为1。
2.m个节点的二叉树的编号均小于m+1个节点的二叉树。
3.m个节点的二叉树的编号为n,满足:所有编号大于n的m个节点的二叉树要么左子树编号比它左子树编号高,要么左子树编号一样,右子树编号比它右子树高。
程序任务为:输入一系列二叉树的编号,分行输出它们对应的树。如果输入为0,则结束。
输出要求:二叉树输出为(L)X(R)的格式,L为左子树,R为右子树。如果左子树为空,则输出格式为X(R);如果右子树为空,输出格式为:(L)X。
示例输入:
1
20
31117532
0
示例输出:
X
((X)X(X))X
(X(X(((X(X))X(X))X(X))))X(((X((X)X((X)X)))X)X)
完成程序。
程序用到了卡特兰数的应用,即n个顶点的二叉树的不同形态数为第n个卡特兰数。
程序接收一系列的输入,直到0结束,并依次输出对应的树。注意在OJ上对程序有着严格的检查,由于是先输入完再统一输出,利用数组存储输入会有数组越界的可能,无论你定义的多大,OJ都会提示Runtime Error(RE)。故应使用链表来存储。
程序首先计算卡特兰数存储以方便使用。对于每一个输入,计算该二叉树为几个节点以及在相同的节点中编号为多少。利用这两个参数调用相应函数,函数通过计算左子树和右子树的对应值来递归调用自身。
程序如下:
(编程语言为C,在OJ中已AC,如有错误,请留言咨询。)
#include "stdio.h"
#include "malloc.h"
#define max 25
int C[max];//卡特兰数,C18基本达到了要求500,000,000.
typedef struct node{
int number;
struct node * next;
}*Node;
void catalan(int C[])
{
int n,i;
C[0]=1;
C[1]=1;
for (n=2; n<max; n++)
{
C[n]=0;
for (i=0; i<n; i++)
{
C[n] += C[i]*C[n-1-i];
}
}
}
void printcatalan(int n, int number)
//输出 n个节点的,编号为number的树
{
int i=0;
if(n == 0)
return;
if(n == 1)
{
printf("X");
return;
}
while(number >=C[i]*C[n-1-i])
{
number -= C[i]*C[n-1-i];
i++;
}
if(i>0)
printf("(");
printcatalan(i,number/C[n-1-i]);//输出左子树
if(i>0)
printf(")");
printf("X");//输出中间节点
if(n-1-i>0)
printf("(");
printcatalan(n-1-i,number%C[n-1-i]);//输出右子树
if(n-1-i>0)
printf(")");
}
int main()
{
int number;
int n=0;
int i=0,j=0;
Node p;
Node N,q;
N = (Node)malloc(sizeof(struct node));
N->next=NULL;
N->number=0;
q = N;
catalan(C);
scanf("%d",&number);
while(number!=0)
{
p = (Node)malloc(sizeof(struct node));
p->next=NULL;
q->next = p;
q = q->next;
p->number = number;
scanf("%d",&number);
}
q = N;
while(q->next != NULL)
{
q = q->next;
number = q->number;
n=0;
while(number>=C[n])
{
number -= C[n];
n++;
}
printcatalan(n,number);//n个节点的,编号为number的树
printf("\n");
}
//第n个卡特兰数的第number个数,0<=number<=C[n]-1
return 0;
}