洛谷 P1087 [NOIP2004 普及组] FBI 树

这篇博客介绍了如何构建FBI树(一种特殊的二叉树),通过输入字符串来生成二叉树,并利用后序遍历进行节点类型的判断。在后序遍历过程中,通过对每个节点的字符串内容检查,确定其是'F'(包含0和1),'B'(仅包含0)还是'I'(仅包含1)类型。此外,还提供了完整的C++代码实现。

P1087 NOIP2004 普及组 FBI 树

菜鸟生成记(39)

思路: 构建二叉树,然后后序遍历(if套if)

#include<iostream>
using namespace std;
typedef struct st{//结点 
	string x;//数据域 
	struct st *r,*l;//指针域 ; 
}ll,*link;//类型名 
void create(link &t,string s)//创建二叉树(这里的树节点一定要用引用类型,不然改变不会回传主函数) 
{
	if(s.length()<=1)//字符串长度<=1,说明已经到达叶子结点了,开始返回 
	{
		t->x=s;//这个赋值不能少,因为长度为1的字符串substr不会再截取了 
		t->l=t->r=NULL;//叶子结点的左右孩子赋空(用于后序遍历判断叶子结点) 
		return;
	}
	else
	{//string截取子串函数:substr(start,len);
	//start:起始下标 len:截取长度
		string str;
		t->l=new ll;//左孩子分配空间 
		str=t->l->x=s.substr(0,s.length()/2);//截取左半 
		create(t->l,str);//创建左子树 
		t->r=new ll;//右孩子分配空间 
		str=t->r->x=s.substr(s.length()/2,s.length());//截取右半 
		create(t->r,str);//创建右子树 
	}
}
void find1(string s)//判断字符串的类型(F,B,I) 
{
	int num1,num0;
	num0=s.find("0");//查找字符串中是否有'0'(有:返回下标,没有: 返回-1) 
	num1=s.find("1");//查找字符串中是否有'1' 
	if(num0!=-1&&num1==-1)//只有0 
	cout<<'B';
	else if(num0==-1&&num1!=-1)//只有1 
	cout<<'I';
	else//有0又有1 
	cout<<'F';
}
void input(link t)//后序遍历二叉树 
{
	if(t)
	{
		input(t->l);
		input(t->r);
		find1(t->x);//判断后输出(F,B,I) 
	}
}
int main()
{
	int n;
	link t=new ll;//根节点分配空间 
	string s;
	cin>>n;
	cin>>s;
	t->x=s;//根节点数据域赋值 
	create(t,s);//创建二叉树 
	input(t);//后序遍历二叉树 
	return 0;
 } 
### 题目解析 题目要求根据一个长度为 $2^N$ 的 01 字符串构造 FBI FBI 是一种二叉树,每个节点类型包括以下三种: - **I 结点**:字符串中全为 1。 - **B 结点**:字符串中全为 0。 - **F 结点**:字符串中既有 0 又有 1。 构造 FBI 的过程是递归的,将字符串分为左右两部分,分别构造左右子,直到字符串长度为 1 时结束。每个节点的类型由其子节点决定,例如: - 若两个子节点都是 I,则父节点为 I。 - 若两个子节点都是 B,则父节点为 B。 - 若两个子节点一个是 I,一个是 B,则父节点为 F。 - 若任意一个子节点是 F,则父节点一定是 F。 #### 输入输出格式 输入包括一个整数 $N$ 和一个长度为 $2^N$ 的 01 字符串。输出为一个字符串,表示 FBI 的后序遍历结果。 #### 示例输入输出 输入: ``` 2 10001111 ``` 输出: ``` IBFBB ``` #### 解题思路 1. **递归构建 FBI **:将字符串分为左右两部分,分别递归构建左右子。 2. **判断节点类型**:在递归返回时判断当前子字符串的类型(I、B 或 F)。 3. **后序遍历输出**:按照左子、右子、根节点的顺序输出结果。 #### AC代码 以下是一个实现 FBI 构造的 C++ 代码示例: ```cpp #include <iostream> #include <string> using namespace std; string s; char getNodeType(int l, int r) { if (l == r) { return s[l] == '1' ? 'I' : 'B'; } int mid = (l + r) / 2; char left = getNodeType(l, mid); char right = getNodeType(mid + 1, r); if (left == right) { return left; } return 'F'; } int main() { int n; cin >> n >> s; int len = (1 << n); // 2^n cout << getNodeType(0, len - 1) << endl; return 0; } ``` ### 算法复杂度分析 - **时间复杂度**:$O(N \cdot 2^N)$,因为每次递归调用都会将字符串分成两部分,递归深度为 $N$,每层处理 $2^N$ 个字符。 - **空间复杂度**:$O(N)$,递归调用栈的最大深度为 $N$。 ### 相关问题 - 如何判断 FBI 的节点类型? - FBI 的构造过程是否可以优化? - 后序遍历 FBI 的具体实现方法是什么? - FBI 与普通二叉树的区别是什么? - 是否可以将 FBI 的构造过程改为非递归实现?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值