# P1087 [NOIP 2004 普及组] FBI 树

## 题目描述

我们可以把由 0 和 1 组成的字符串分为三类:全 0 串称为 B 串,全 1 串称为 I 串,既含 0 又含 1 的串则称为 F 串。

FBI 树是一种二叉树,它的结点类型也包括 F 结点,B 结点和 I 结点三种。由一个长度为 2^N 的 01 串 S 可以构造出一棵 FBI 树 T,递归的构造方法如下:

1. T的根结点为 R,其类型与串 S 的类型相同;
2. 若串 S 的长度大于 1,将串 S 从中间分开,分为等长的左右子串 S_1 和 S_2;由左子串 S_1 构造 R 的左子树 T_1,由右子串 S_2 构造 R的右子树 T_2。

现在给定一个长度为 $2^N$ 的 01 串,请用上述构造方法构造出一棵 FBI 树,并输出它的后序遍历序列。

## 输入格式

第一行是一个整数 N(0 \le N \le 10),  

第二行是一个长度为 2^N 的 01 串。

## 输出格式

一个字符串,即 FBI 树的后序遍历序列。

##输入输出样例#1

###输入#1

```
3
10001011
```

###输出#1

```
IBFBBBFIBFIIIFF
```

noip2004普及组第3题

函数 build(l, r)处理子串 s[l..r]:
如果 l == r,根据 s[l]返回 "B"或 "I"。否则,计算中点 mid = (l + r) / 2,递归得到左子树后序 left_str和右子树后序 right_str。
判断当前子串类型:
如果全 0→ "B"。如果全 1→ "I",否则 → "F"。返回 left_str + right_str + ,当前节点类型判断全 0 / 全 1​,可以在递归时传入子串范围,检查该范围内是否所有字符相同且为 '0'或 '1'。
代码如下:
#include <iostream>
#include <string>
using namespace std;

string s;
int n;

// 判断子串 s[l..r] 是否全为 ch
bool allChar(int l, int r, char ch) {
    for (int i = l; i <= r; i++) {
        if (s[i] != ch) return false;
    }
    return true;
}

// 递归构建后序遍历
string build(int l, int r) {
    if (l == r) {
        if (s[l] == '0') return "B";
        else return "I";
    }
    
    int mid = (l + r) / 2;
    string leftStr = build(l, mid);
    string rightStr = build(mid + 1, r);
    
    // 判断当前节点类型
    bool has0 = !allChar(l, r, '1');
    bool has1 = !allChar(l, r, '0');
    
    string nodeType;
    if (!has0 && has1) nodeType = "I";
    else if (has0 && !has1) nodeType = "B";
    else nodeType = "F";
    
    return leftStr + rightStr + nodeType;
}

int main() {
    cin >> n;
    cin >> s;
    int len = 1 << n; // 2^n
    // 确保长度正确
    s = s.substr(0, len);
    cout << build(0, len - 1) << endl;
    return 0;
}
全部评论

相关推荐

12-07 10:09
复旦大学 Java
点赞 评论 收藏
分享
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务