#
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;
}