一年一度的研究生面试又快要来临了。为了测试学生对树结构的认识,同时也检验他们的编程能力,福州大学计算机系把面试的一项内容定为:要求学生们编程按编号顺序打印出节点个数不少于m的所有二叉树。
二叉树编号规则如下:
仅有一个节点的树编号为1。
当满足以下条件之一时,定义二叉树a的编号比b大:
1. a的节点数比b多。
2. 若a的节点数与b相等,且a的左子树编号比b的左子树大。
3. a的节点数和左子树编号都和b相等,且a的右子树编号比b的右子树大。
二叉树的节点用大写X表示,例如:
当然当m较大时,检验答案对错的工作也是很繁重的,所以教授只打算对其中的若干个编号的二叉树进行抽查,他想麻烦你编制一个程序能够产生编号为n的二叉树的标准答案。
Input
输入数据由多组数据组成。每组数据仅一个整数,表示n (1≤n≤10^8)的值。输入数据以n=0表示结束,该数据不要处理。
Output
对于每组数据,输出仅一行,即你求出的标准答案。
二叉树的输出格式为:
(左子树){若左子树为空则省略}X{根}(右子树){若右子树为空则省略}
其中{…}中的内容是说明,不必输出。例如,在上图中编号为5的树可表示为X((X)X);编号为6的树表示为(X)X(X)。
Sample Input
20
0
Sample Output
((X)X(X))X
分析:
通过数据量可以看出,这个题肯定是先寻找规律,然后递归输出。
然而,问题就在于,这规律怎么找,还有这该死的括号。
可也正是这个该死的括号,渐渐引导人们想起卡特兰数,自然我是好久想不出来的。
卡特兰数公式:
h(n)=h(n−1)∗(4∗n−2)/(n+1);
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e3 + 10;
#define ll long long int
ll f[maxn];
int n;
bool flag;
void get_f(int x, int y)
{
if (x == 0)
return;
for (int i = 0; i < x; i++)
{
if (y <= f[i] * f[x - i - 1])
{
if (flag)
{
printf("(");
get_f(i, (y - 1) / f[x - i - 1] + 1);
printf("X");
get_f(x - i - 1, (y - 1) % f[x - i - 1] + 1);
printf(")");
}
else
{
flag = 1;
get_f(i, (y - 1) / f[x - i - 1] + 1);
printf("X");
get_f(x - i - 1, (y - 1) % f[x - i - 1] + 1);
}
break;
}
else
{
y -= f[i] * f[x - i - 1];
}
}
}
int main()
{
f[0] = f[1] = 1;
for (int i = 2; i < maxn; i++)//ka te lan
{
f[i] = 1ll * f[i - 1] * (4 * i - 2) / (i + 1);
}
while (~scanf("%d", &n)&&n)
{
flag = 0;
for (int i = 1; i < maxn; i++)
{
if (n <= f[i])
{
get_f(i, n);
break;
}
else
{
n -= f[i];
}
}
printf("\n");
}
return 0;
}