#
1、小写字母“o”表示结点,对于一个父亲结点,分别用“/”、“\”连接左、右子树。
2、定义[i,j]为位于第i行,第j列的某个字符。若[i,j]为“/”,那么[i-1,j+1]与[i+1,j-1]只可能是“o”或者“/”。若[i,j]为“\”,那么[i-1,j-1]与[i+1,j+1]只可能是“o”或者“\”。同样,若[i,j]为第1-m层的某个节点(即“o”),那么[i+1,j-1]为“/”,[i+1,j+1]为“\”。3、对于第m层节点也就是叶子结点,若两个属于同一个父亲,那么它们之间由3个空格隔开,若两个结点相邻但不属于同一个父亲,那么它们之间由1个空格隔开。第m层左数第1个节点之前没有空格。
最后需要在一颗绘制好的满二叉树上删除n个结点(包括它的左右子树,以及与父亲的连接),原有的字符用空格替换(ASCII 32)。
#include<iostream>
#include<cmath>
using namespace std;
const int maxn=1<<10|1;
int tree[maxn];
int del_count=0;
int m,n,total,w,h,last;
char p[1<<11][1<<11];
int get_id(int x,int y){
return pow(2,x-1)-1+y;
}
void del(int id){
if (id>total) return;
tree[id]=0;
del(id*2);
del(id*2+1);
} //删节点
void draw(int id,int& x,int& y){
if (id>last){
int tmp=id-last;
x=h;
y=6*((tmp-1)/2)+(tmp%2!=0?1:5);
if (tree[id]) p[x][y]='o';
else del_count++;
return;
}
int lx,ly,rx,ry;
draw(id<<1,lx,ly);
draw(id<<1|1,rx,ry);
y=(ly+ry)/2;
x=lx-(ry-ly)/2;
if (tree[id]){
p[x][y]='o';
for (int i=1;i<(ry-ly)/2;i++){
if (tree[id*2])p[x+i][y-i]='/';
if (tree[id*2+1]) p[x+i][y+i]='\\';
}
}
else {
del_count++;
}
}//绘制
int main(){
cin>>m>>n;
total=pow(2,m)-1;
int n0=pow(2,m-1);
w=n0/2*5+n0/2-1;
h=w/2+1;
last=pow(2,m-1)-1;
for (int i=1;i<=(1<<m);i++){
tree[i]=1;
}
for (int i=1;i<=n;i++){
int x,y;
cin>>x>>y;
int id=get_id(x,y);
del(id);
}
int x,y;
draw(1,x,y);
cout<<total-del_count<<"\n";
for (int i=1;i<=h;i++){
for (int j=1;j<=w;j++){
if (p[i][j]=='o'||p[i][j]=='/'||p[i][j]=='\\'){
cout<<p[i][j];
}
else cout<<" ";
}
cout<<"\n";
}
return 0;
}