【传送门】https://www.luogu.org/problemnew/show/P1087
【题解】本题主要考察树的遍历,要求对递归有深刻的理解。
1、建树。按照题意,建树的过程实际上是先序遍历,即先根,再左子树、右子树。当字符串长度为1时,读入根结点值后令左、右指针为NULL。当字符串长度大于1时,读入根结点值后再递归建立左、右子树。
2、判断。判断当前节点的FBI树类型,令int B=1,I=1,然后遍历当前节点,如果遇到'0',令I=0,表示有'0';如果遇到'1',令B=0,表示有'1'。如果B=1没有改变,说明全为'0';如果I=1没有改变,说明节点全为'1'。两个都有改变,则说明节点既有'0',又有'1'。
3、输出。输出过程是对树的后序遍历(先左、右子树,再根节点)。可以和建树过程集成在一起,也就是递归建立左子树、右子树退出后输出根结点值。但为了练习如何建树,如何输出遍历,下面题解没有这样做。
【AC代码1】孩子表示法,链式存储结构,指针建树
//lg p1087 FBI树 AC代码 通过此题学习用指针建树,孩子表示法
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=(1<<10)+5;
int n=3;
char str[maxn]="10001011";
struct node{ //自引用结构。
char data;
node *lt,*rt;
/*
“node *lt,*rt;”
如果写成“node lt”,则属于非法,因为lt是另一个完整的结构,其内部还将包含它自己的成员lt,
这第二个lt又是一个完整的结构,它还将包含自己的成员lt。
但写成“node *lt;”,则合法,因为现在lt不是结构体,而是一个指针,编译器知道指针的长度。
*/
};
node *T;//申明一个指针,指向结构体node。在定义结构体时并不分配内存,只有定义了结构体变量时才分配,初始为NULL
void make_tree(node *T,int l,int r){//*不能少,否则编辑错误。申明T是指向node的指针
//判断根树是'F'或'B'或'I'
int B=1,I=1;
for(int i=l;i<=r;i++){
if(str[i]=='1')B=0;
else I=0;
}
if(B)T->data='B';//这里的T是指针,从而写成T->data。如果申明node U,则写成U.data。回到本行代码,也可以写成(*T).data。
else if(I)T->data='I';
else T->data='F';
//递归建树
if(l<r){
T->lt=new node;T->rt=new node;
make_tree(T->lt,l,(l+r)/2);
make_tree(T->rt,(l+r)/2+1,r);
}
else{
T->lt=new node;T->rt=new node;//这句话可以省略不写
T->lt=NULL;
T->rt=NULL;
}
}
void print(node* T){ //*不能少,否则编辑错误。申明T是指针
if(T){
print(T->lt);
print(T->rt);
printf("%c",T->data);
}
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%s",&n,str);
T=new node;//要求先申请新内存才可以对T进行操作
//cout<<T<<endl;
make_tree(T,0,(1<<n)-1); //1<<n-1先运算n-1,再左移。(1<<n)-1先运算左移,再减1
//cout<<T<<endl;
print(T);
return 0;
}
【AC代码2】递归,不建树
//lg p1087 FBI树 不建树的写法,用递归
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1<<10+5;
int n=3;
char str[maxn]="10001011";
void mk(int l,int r){
//判断根是'F'或'B'或'I'
int B=1,I=1;
for(int i=l;i<=r;i++){
if(str[i]=='1')B=0;
else I=0;
}
int c;
if(B)c='B';
else if(I)c='I';
else c='F';
//递归
if(l<r){
mk(l,(l+r)/2);//左
mk((l+r)/2+1,r);//右
printf("%c",c);//根
}
else printf("%c",c);//根
}
int main(){
scanf("%d%s",&n,str);
mk(0,(1<<n)-1);
return 0;
}