/*
* poj 1095 二叉树编号
题目大意:
二叉树按照如下规则进行编号:
1、0个节点的空树编号为0
2、单个节点的树编号为1
3、任意包含m个节点的二叉树,其编号必然小于任意一个包含m+1个节点的二叉树
4、包含相同节点的二叉树,左子树如果相同,大小取决于右子树的大小比较,如果
左子树不同,则大的编号较大。公式如下:
|-- n(L(T1)) > n(L(T2))
n(T1) > n(T2) --|
|-- n(L(T1))= n(L(T2)) && n(R(T1)) > n(R(T2))
求给定序号的二叉树打印.
数学模型:
令f(m)表示包含m个节点的二叉树的个数,则有如下公式成立:
f(m) = sum{f(k)*f(m-1-k) | k->0~m-1}
解题思路:
本题与poj 1019数列问题有点象,同样是打印出序号为n的元素。解法也类似
1、根据上面求出的f(m)数组,可以判断出给定的序号为n的二叉树包含的节点个数
2、然后枚举右子树的元素个数(从m-1到0),找出左右子树的元素个数
3、
*/
#include <stdio.h>
#define M_MAX 18
unsigned int f[M_MAX+1];
/*
打印包含m个节点的,内部编号为num的二叉树。递归实现
*/
void m_tree_print(int m, unsigned int num)
{
int l, r, l_th, r_th;
if(m==1) {printf("X");return ;}
if(m==2)
{
if(num==1) printf("X(X)");
else printf("(X)X");
return ;
}
// 计算右子树包含节点数
for (r=m-1; r>=0; r--)
{
if (num <= f[r]*f[m-1-r]) break;
num -= f[r]*f[m-1-r];
}
// 计算右子树包含节点数
l = m-1-r;
// 计算左子树内部编号 -- 从1开始
for (l_th=1; true; l_th++)
{
if (num <= f[r]) break;
num -= f[r];
}
// 右子树内部编号 -- 从1开始
r_th = num;
// 打印左子树
if (l!=0)
{
printf("(");
m_tree_print(l, l_th);
printf(")");
}
// 打印根节点
printf("X");
// 打印右子树
if (r!=0)
{
printf("(");
m_tree_print(r, r_th);
printf(")");
}
}
/*
打印外部编号为nth的二叉树
*/
void nth_tree_print(unsigned int nth)
{
int m=1, m_nth=nth;
// 计算二叉树包含的节点数m
for (; m<=M_MAX; m++)
{
if (m_nth <= f[m]) break;
m_nth -= f[m];
}
m_tree_print(m, m_nth);
}
int main()
{
unsigned int nth;
// 打表,计算各m个节点二叉树所占个数
f[0]=1;
for (int m=1; m<=M_MAX; m++)
{
for (int k=0; k<m; k++)
{
f[m] += f[k]*f[m-1-k];
}
}
scanf("%d", &nth);
while (nth!=0)
{
nth_tree_print(nth);
printf("\n");
scanf("%d", &nth);
}
return 0;
}
poj 1095 二叉树的编号
最新推荐文章于 2022-05-11 09:59:35 发布