这道题更像一道数学题,说实话,数学规律找得越好,解题越快,其他思路倒是对解题没有什么太大的帮助吧
只要给出确定层数
那么层与层之间的高度差可以被直接计算出来
也就是每一层所在二维字符数组中的纵坐标可以被计算出来
当二叉树确定之后,如果给定确定的第几层第几个结点,也可以把这个结点的坐标计算出来
如果给定层级,也可以把这个层级的结点所影响到的范围也计算出来
这样
我们便可以根据给定的层级
建造出相应的二叉树
通过给定结点
计算出节点位置和节点的影响范围
然后把整个结点的影响范围删除,结点影响的整个范围不好计算,还是递归删除把
递归参数需要点的坐标,
如果是向下遍历,则需要见到什么删除什么
如果向上遍历,则需要遇到o就需要停止,不可以把父节点删除奥。
ok:
出现错误:没有正确打印出结点
1.数组中出现了问题,d数组的第二项没有进行预处理,而这一项不符合我们的规律
2.creatnode函数出现问题,每一层打印节点数多了,因为应该在设置过程中内层循环j<Pow(high-i),我写成了j<Pow(high)了。内层循环的变化问题,需要反思
3.creatlink函数也出现了问题
表现为没有正确的判断标记和递归情况导致出错了。
表现相当完美
现在只需要倒着打印出来就好了。
痛哭流涕!!!!!
只得了44分
经测试:错误1,对于最底层结点删除出现了问题,我delet内层的两个函数看来出现了弊端,没办法删除当前结点
错误2,cal函数出现问题。
现在是77分,还有两个测试点没有解决,看来有一个问题是数组越界了,开的不够大,过了yes
总结一下我的思路:
1.先计算,保证给出层数,可以到的纵坐标,每层第一个的横坐标,和每层之间结点之间的距离
2.读取层数,做出相应层数的完整二叉树
3.做二叉树,根据计算公式先做结点
4.把父结点的坐标,根据这个递归,把链子做出来
5.读取删除结点,转化为坐标
6.根据删除结点坐标,进行上和下递归,保证删除所有有关联的结点和链子
遇到的错误
1.没有正确地进行预处理
2.双层循环,内部循环条件需要由外部循环决定,而我设置成了定值
3.递归的时候,没有正确判断情况
4.删除函数逻辑出现问题,不可以很好地处理边界情况
5.横纵坐标写反了,数组前者是纵坐标,后者是横坐标
6.数组开小了
总归是一道很难的题(对我来说)
如果以后的我想要提升,那么看一看大佬的代码吧,但是我现在已经看不进去了。
放代码:
#include<stdio.h>
#define maxn 3000
//结构体
typedef struct
{
int x,y;
}Point;
Point a;
int high=0,n=0,ceng=0,cnt=0,hx[15]={0},hy[15]={0},d[15]={0};
char tree[maxn][maxn];
//hy这个数组,用于记录第k行的第一个元素的下标
//函数
void ahead();
Point cal(int height,int num);
void deletf(int x,int y);
void delets(int x,int y);
void print();
void creat(int n);
void creatnode(int n);
void creatlink(int x,int y);
void delet(int x,int y);
int Pow(int n);
int main()
{
scanf("%d %d",&high,&n);
ahead();
creat(high);
for(int i=1;i<=n;i++)//读取并删除n个结点
{
scanf("%d %d",&ceng,&cnt);
a=cal(high-ceng+1,cnt);//转化为坐标
delet(a.x,a.y);
}
print();//打印这个树
}
void ahead()
{
hx[1]=1,hx[2]=3;
d[1]=3,d[2]=5;
hy[1]=1,hy[2]=3;
for(int i=3;i<=10;i++)//十层基础数据拿下,这里面的第一层实际上是最后一层
{
d[i]=2*d[i-1]+1;
hx[i]=(d[i-1]-1)/2+1+hx[i-1];
hy[i]=hx[i];
}//预处理
}
Point cal(int height,int num)//第几层第几个
{
Point a;
if(height==1)
{
a.x=1;
if(num%2==0)
{
a.y=3*num-1;
}
else
{
a.y=3*num-2;
}
}
else
{
a.x=hx[height];
a.y=hy[height]+(cnt-1)*(d[height]+1);
}
return a;
}
//递归删除
void delet(int x,int y)
{
deletf(x,y);
delets(x,y);
tree[x][y]=' ';
return ;
}
void deletf(int x,int y)//一直遍历搜索,删除相连点
{
if(tree[x+1][y-1]=='/')//左下角是这个
{
x=x+1;
y=y-1;
while(tree[x][y]!='o')
{
tree[x][y]=' ';
x=x+1;
y=y-1;
}
}
else if(tree[x+1][y+1]=='\\')
{
x=x+1;
y=y+1;
while(tree[x][y]!='o')
{
tree[x][y]=' ';
x=x+1;
y=y+1;
}
}
}
void delets(int x,int y)//向上,因为我的树是反过来的
{
if(tree[x][y]=='o')//是o,则需要判断两端子树
{
tree[x][y]=' ';//左上相当于左下,x-1,y-1;
if(tree[x-1][y-1]=='\\')//判断'\'需要写成'\\'
{
delets(x-1,y-1);
}
if(tree[x-1][y+1]=='/')
{
delets(x-1,y+1);
}
}
else if(tree[x][y]=='\\')
{
//直接删除,然后向左上方遍历即可
tree[x][y]=' ';
delets(x-1,y-1);
}
else if(tree[x][y]=='/')
{
tree[x][y]=' ';
delets(x-1,y+1);
}
//其它一概不管
return ;
}
void print()
{
for(int i=hx[high];i>=1;i--)//一共多少层,而且从最上面开始
{
for(int j=1;j<=5*Pow(high-1);j++)//一共有多少列第一层最多
{
if(tree[i][j]=='o')
{
printf("o");
}
else if(tree[i][j]=='\\')
{
printf("/");
}
else if(tree[i][j]=='/')
{
printf("\\");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
void creat(int n)
{
creatnode(n);
//创造出来之后,还要把第n层的y和x求出来,也就是hx[high]和hy[high]
creatlink(hx[high],hy[high]);
return ;
}
void creatnode(int n)//多打印或者少打印问题
{
//从第一层,开始向下打印出n个结点,其中只有第一层比较难打印
//外层就是层数,内层循环就是结点数
int y=1;
for(int i=1;i<=high;i++)
{
y=hy[i];//y就是第i层第一个点的横坐标
for(int j=1;j<=Pow(high-i);j++)//记录一共打印了多少个结点
{
if(i==1)//第一层特殊对待
{
//分情况讨论,如果当前j是奇数,那么需4,如果是偶数需要加2
tree[hx[i]][y]='o';
if(j%2==1)
{
y=y+4;
}
else
{
y=y+2;
}
}
else//非第一层对待
{
tree[hx[i]][y]='o';
y=y+d[i]+1;
}
}
}
return ;
}
void creatlink(int x,int y)//给入父节点坐标,开始连线
{
if(x==1)//如果当x==1,直接完事了
{
return ;
}
if(tree[x][y]=='o')//左右生根发芽
{
//先给出我们需要的,然后直接填就可以了
tree[x-1][y-1]='\\';
tree[x-1][y+1]='/';
creatlink(x-1,y-1);//左上左上方应该填
creatlink(x-1,y+1);//右上
}
if(tree[x][y]=='\\')
{
if(tree[x-1][y-1]!='o')
{
tree[x-1][y-1]='\\';
}
creatlink(x-1,y-1);//左上左上方应该填
}
if(tree[x][y]=='/')
{
if(tree[x-1][y+1]!='o')
{
tree[x-1][y+1]='/';
}
creatlink(x-1,y+1);//右上
}
return ;
}
int Pow(int n)
{
int sum=1;
for(int i=1;i<=n;i++)
{
sum=sum*2;
}
return sum;
}