【题目链接】
ybt 1365:FBI树(fbi)
ybt 1928:【04NOIP普及组】FBI树
洛谷 P1087 [NOIP2004 普及组] FBI 树
【题目考点】
1. 二叉树
【解题思路】
设树中结点类型,包含char类型的val成员变量,意为结点的类型,可以是’F’, ‘B’或’I’。
估算该问题可能用到的最大结点数。易知FBI树是满二叉树,FBI串最长有 2 N 2^N 2N,N最大是10,也就是说这个树的叶子结点最多有 2 10 2^{10} 210 个,整棵树的结点数为 2 0 + 2 1 + . . . + 2 10 = 1 ( 1 − 2 11 ) 1 − 2 = 2 11 − 1 = 2047 2^0+2^1+...+2^{10}=\frac{1(1-2^{11})}{1-2}=2^{11}-1=2047 20+21+...+210=1−21(1−211)=211−1=2047,数组长度设为2050刚刚好。
设函数createTree,参数为fs。意为:根据FBI串fs来构建一棵二叉树。
FBI串的长度都是2的整数幂,下表从0开始,长度为fs.length()
。那么fs.length()/2
为中间偏右的位置。左半边下标范围为0~fs.length()/2-1
,右半边下标范围为fs.length()/2
~fs.length()-1
。取子串得到左右子树的FBI串,递归调用本函数根据FBI串生成左右子树。
- 若左右子树根结点的类型相同,那么这棵树根结点也是这个类型(左右子树根结点的类型如果都是I,那么根结点类型也为’I’;若都是’B’, 根结点类型为’B’)。
- 若左右子树根结点的类型不同,那么这棵树根结点的类型为’F’。
递归出口为:如果FBI串fs长度为1,那么这个结点是叶子结点。看这个字符串中的唯一的字符来确定这个结点的val。
- 如果是’1’,那么这个叶子结点的val为’I’。
- 如果是’0’, 那么这个叶子结点的val为’B’。
得到树后,对这棵树做后序遍历。
【题解代码】
解法1:使用string类
#include <bits/stdc++.h>
using namespace std;
#define N 2050
struct Node
{
char val;//结点类型,可以是'F', 'B', 或'I'
int left, right;
};
Node node[N];//结点池
int n, p;
string s;
int createTree(string fs)//根据FBI串fs构建二叉树,返回二叉树的根
{
int np = ++p;
if(fs.length() == 1)
{
node[np].val = fs[0] == '1' ? 'I' : 'B';
return np;
}
string ls = fs.substr(0, fs.length()/2), rs = fs.substr(fs.length()/2);
int lp = createTree(ls), rp = createTree(rs);
node[np].left = lp, node[np].right = rp;
if(node[lp].val == node[rp].val)
node[np].val = node[lp].val;//如果二者相同,那么父节点
else
node[np].val = 'F';
return np;
}
void postOrder(int r)
{
if(r == 0)
return;
postOrder(node[r].left);
postOrder(node[r].right);
cout << node[r].val;
}
int main()
{
cin >> n >> s;
int root = createTree(s);
postOrder(root);
return 0;
}
解法2:使用字符数组
#include <bits/stdc++.h>
using namespace std;
#define N 2050
struct Node
{
char val;
int left, right;
};
Node node[N];
int p;
char s[N];
int createTree(int l, int r)//通过s[l]~s[r]的字符串建立FBI树,返回树根结点的地址
{
int np = ++p;
if(l == r)
{
if(s[l] == '0')
node[np].val = 'B';
else
node[np].val = 'I';
return np;
}
int lp = createTree(l, (l+r)/2), rp = createTree((l+r+1)/2, r);//(l+r+1)/2是中间偏右位置
node[np].left = lp, node[np].right = rp;
if(node[lp].val == node[rp].val)
node[np].val = node[lp].val;
else
node[np].val = 'F';
return np;
}
void postOrder(int r)
{
if(r == 0)
return;
postOrder(node[r].left);
postOrder(node[r].right);
cout<<node[r].val;
}
int main()
{
int n, n1;
cin >> n1;
n = (int)pow(2,n1);//n:字符串总长度
cin >> s;
int root = createTree(0, n-1);
postOrder(root);
return 0;
}