Trees Made to Order
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 362 Accepted Submission(s): 208
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:
Your job for this problem is to output a binary tree when given its order number.
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.
先計算 f [i],保存有 i 個節點的樹可有多少個,在每個節點試探左兒子有多少個節點,右兒子有多少節點,然後進行一些細節的計算。
比如得到左兒子節點數後,就知道左兒子是那種樹(節點數相同是一種樹),這時再計算左兒子應該是這種樹中的第幾棵。
雖然已經儘量追求代碼整潔了,但是代碼還是比較醜。。。
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <algorithm>
#include <numeric>
#define MAXN 100
long long f [MAXN];
void print_tree (long long n) {
#ifdef _DEBUG
printf ("n = %lld\n", n);
#endif
if (n == 0) {
return;
} else if (n == 1) {
printf ("X");
return;
}
long long nodes = 0;
long long count = 0;
while (count <= n) {
count += f [nodes++];
}
count -= f [--nodes];
long long l_nodes = 0;
long long r_nodes = nodes - 1 - l_nodes;
long long d = 0;
while (count + d <= n) {
d += f [l_nodes++] * f [r_nodes--];
}
d -= f [--l_nodes] * f [++r_nodes];
long long t = n - count - d;
long long l_n = std::accumulate (f, f + l_nodes, 0) + t / f [r_nodes];
long long r_n = std::accumulate (f, f + r_nodes, 0) + t % f [r_nodes];
if (l_n) {
printf ("(");
print_tree (l_n);
printf (")");
}
printf ("X");
if (r_n) {
printf ("(");
print_tree (r_n);
printf (")");
}
}
int main () {
memset (f, 0, sizeof (f));
long long sum = 0;
f [0] = f [1] = 1;
for (int i=2; i<MAXN; ++i) {
for (int k=0; k<i; ++k) {
f [i] += f [k] * f [i - k - 1];
}
if ((sum += f [i]) > 5000000000LL) {
break;
}
}
#ifdef _DEBUG
for (int i=0; i<20; ++i) {
printf ("%lld%s", f [i], i==19 ? "\n" : " ");
}
#endif
long long n;
while (scanf ("%lld", &n) == 1 && n) {
print_tree (n);
printf ("\n");
}
return 0;
}