这道题我有一个满级思路
题目描述
我们可以把由“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从中间分开,分为等长的左右子串S1和S2;由左子串S1构造 R的左子树T1,由右子串S2构造R的右子树T2。
现在给定一个长度为2^N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历序列。
输入
第一行是一个整数N(0 <= N <= 10),第二行是一个长度为2^N的“01”串。
输出
包括一行,这一行只包含一个字符串,即FBI树的后序遍历序列。
样例输入
3 10001011
样例输出
IBFBBBFIBFIIIFF
题目分析
题目让我们先求出二叉树,并求出它的后序遍历。
后序遍历是深度优先遍历二叉树的一种方法,它的递归定义是:先后序遍历左子树,再后序遍历右子树,最后访问根。
输入n(其实n+1表示的是树的深度)
输入“01”串(表示的是叶子节点存储的数)
让我们看下图(样例)
解:由题可知,由图可知。
下面做法对于我这种不会数据结构的小菜鸡
先推二叉树叶子节点
1 对应的是 I,0 对应的是 B,那我们可以将“01”串转为“FBI”串。
10001011 转化为 IBBBIBII
cin>>n>>b; //输入n 和 "01"串
l=strlen(b); //获取串的长度
for(long long i=0;i<l;i++) //将"01"串转为FBI串
{
if(b[i]=='1') a[n+1][i]='I'; //1对应 I n+1为二叉树的深度
if(b[i]=='0') a[n+1][i]='B'; //0对应 B
}
再向上推二叉树的父节点
左子节点 | 右子节点 | 父节点 |
I | I | I |
B | B | B |
I | B | F |
B | I | F |
其中一个节点为F | F或B或I | F |
char hs(char x,char y) //推法
{
if(x=='I'&&y=='I') return 'I'; //左右子节点都为 I 父节点为 I
if(x=='B'&&y=='B') return 'B'; //左右子节点都为 B 父节点为 B
if(x=='I'&&y=='B') return 'F'; //左子节点为 I 右子节点为 B 父节点为 F
if(x=='B'&&y=='I') return 'F'; //左子节点为 B 右子节点为 I 父节点为 F
if(x=='F'||y=='F') return 'F'; //其中一个子节点为 F 父节点为 F
}
for(long long i=n;i>=1;i--) //开始从下往上推根节点
{
l/=2; //每层的节点数为上一层节点数的一半
for(long long j=0;j<l;j++)
{
a[i][j]=hs(a[i+1][j+j],a[i+1][j+1+j]); //二维数组模拟二叉树
}
}
结合一下,便可以得到FBI二叉树的模型
见下
#include<bits/stdc++.h>
using namespace std;
long long n,l;
char b[1027],a[15][1027];
char hs(char x,char y)
{
if(x=='I'&&y=='I') return 'I';
if(x=='B'&&y=='B') return 'B';
if(x=='I'&&y=='B') return 'F';
if(x=='B'&&y=='I') return 'F';
if(x=='F'||y=='F') return 'F';
}
int main()
{
cin>>n>>b;
l=strlen(b);
for(long long i=0;i<l;i++)
{
if(b[i]=='1') a[n+1][i]='I';
if(b[i]=='0') a[n+1][i]='B';
}
for(long long i=n;i>=1;i--)
{
l/=2;
for(long long j=0;j<l;j++)
{
a[i][j]=hs(a[i+1][j+j],a[i+1][j+1+j]);
}
}
for(long long i=1;i<=n+1;i++) //输出
{
for(long long j=0;j<l;j++)
{
cout<<a[i][j]<<" ";
}
cout<<endl;
l*=2; //从上往下节点数*2
}
return 0;
}
好了,现在二叉树出来了,只剩下后序遍历了。
用数组实现的话,只用在建二叉树时记录每个节点的父节点,最好再递归查询就行了。
详细请看代码注释
void dg(long long x,long long y) //输出父节点
{
if(bz[x][y]!=2) //左子节点和右子节点没遍历完就返回
{
return;
}
cout<<a[x][y]; //输出父节点
bz[xx[x][y]][yy[x][y]]++; //父节点的父节点 标记+1 表示已被遍历
dg(xx[x][y],yy[x][y]); //注意xx(i,j) yy(i,j)保存的是父节点的位置,见第36行
}
for(long long i=n;i>=1;i--) //建二叉树 不多说
{
l/=2;
for(long long j=0;j<l;j++)
{
xx[i+1][j+j]=i,xx[i+1][j+1+j]=i; //子节点记录父节点的位置(i,j)
yy[i+1][j+j]=j,yy[i+1][j+1+j]=j;
a[i][j]=hs(a[i+1][j+j],a[i+1][j+1+j]);
}
}
for(long long i=n+1;i>=1;i--) //从下往上后序遍历
{
for(long long j=0;j<=pow(2,(i-1));j++) //pow(2,(i-1))为第i层的节点数
{
if(bz[i][j]==2) continue; //bz[i][j]==2 表示父节点、左子节点、右子节点都遍历了
cout<<a[i][j]; //没标记就输出
bz[xx[i][j]][yy[i][j]]++; //父节点 标记+1 表示输出了一个子节点
dg(xx[i][j],yy[i][j]); //递归输出父节点,第45行就不用再输出一次父节点了
}
}
最后全部加起来,结果算出来,你学会了吗
见下
#include<bits/stdc++.h>
using namespace std;
long long n,l,bz[15][1027],xx[15][1027],yy[15][1027];
char b[1027],a[15][1027];
char hs(char x,char y)
{
if(x=='F'||y=='F') return 'F';
if((x=='1'||x=='I')&&(y=='1'||y=='I')) return 'I';
if((x=='0'||x=='B')&&(y=='0'||y=='B')) return 'B';
if((x=='1'||x=='I')&&(y=='0'||y=='B')) return 'F';
if((x=='0'||x=='B')&&(y=='1'||y=='I')) return 'F';
}
void dg(long long x,long long y)
{
if(bz[x][y]!=2)
{
return;
}
cout<<a[x][y];
bz[xx[x][y]][yy[x][y]]++;
dg(xx[x][y],yy[x][y]);
}
int main()
{
cin>>n>>b;
l=strlen(b);
for(long long i=0;i<l;i++)
{
a[n+1][i]=hs(b[i],b[i]);
}
for(long long i=n;i>=1;i--)
{
l/=2;
for(long long j=0;j<l;j++)
{
xx[i+1][j+j]=i,xx[i+1][j+1+j]=i;
yy[i+1][j+j]=j,yy[i+1][j+1+j]=j;
a[i][j]=hs(a[i+1][j+j],a[i+1][j+1+j]);
}
}
for(long long i=n+1;i>=1;i--)
{
for(long long j=0;j<=pow(2,(i-1));j++)
{
if(bz[i][j]==2) continue;
cout<<a[i][j];
bz[xx[i][j]][yy[i][j]]++;
dg(xx[i][j],yy[i][j]);
}
}
return 0;
}
完结撒花!!!!!!!!!!!!!!!!!!!