【洛谷P1185】绘制二叉树

二叉树题单的最后一道题

没有什么硬性知识 就是递归的简单应用

P1185 绘制二叉树

题目描述

二叉树是一种基本的数据结构,它要么为空,要么由根结点,左子树和右子树组成,同时左子树和右子树也分别是二叉树。

当一颗二叉树高度为 \(m-1\) 时,共有 \(m\) 层。若一棵二叉树除第 \(m\) 层外,其他各层的结点数都达到最大,且叶子结点都在第 \(m\) 层时,则其为一棵满二叉树。

现在,需要你用程序来绘制一棵二叉树,它由一棵满二叉树去掉若干结点而成。对于一棵满二叉树,我们需要按照以下要求绘制:

  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\sim m-1\) 层的某个结点 o ,那么 \([i+1,j-1]\)/\([i+1,j+1]\)\

  3. 对于第 \(m\) 层结点也就是叶子结点点,若两个属于同一个父亲,那么它们之间由 \(3\) 个空格隔开;若两个结点相邻但不属于同一个父亲,那么它们之间由 \(1\) 个空格隔开。第 \(m\) 层左数第 \(1\) 个结点之前没有空格。

最后需要在一棵绘制好的满二叉树上删除 \(n\) 个结点(包括这个结点的左右子树,以及与父亲的连接),原有的字符用空格替换(空格为 ASCII 32,若输出 ASCII 0 会被算作错误答案)。

输入格式

\(1\) 行包含 \(2\) 个正整数 \(m\)\(n\),为需要绘制的二叉树层数和需要删除的结点数。

接下来 \(n\) 行,每行两个正整数,表示删除第 \(i\) 层的第 \(j\) 个结点。

输出格式

按照题目要求绘制的二叉树。

输入输出样例 #1

输入 #1

2 0

输出 #1

o  
 / \ 
o   o

输入输出样例 #2

输入 #2

4 0

输出 #2

o           
          / \          
         /   \         
        /     \        
       /       \       
      /         \      
     o           o     
    / \         / \    
   /   \       /   \   
  o     o     o     o  
 / \   / \   / \   / \ 
o   o o   o o   o o   o

输入输出样例 #3

输入 #3

4 3
3 2
4 1
3 4

输出 #3

o           
          / \          
         /   \         
        /     \        
       /       \       
      /         \      
     o           o     
    /           /      
   /           /       
  o           o        
   \         / \       
    o       o   o

说明/提示

\(30\%\) 的数据满足:\(n=0\)

\(50\%\) 的数据满足:\(2\le m\le 5\)

\(100\%\) 的数据满足:\(2\le m\le10,0\le n\le 10,1<i\le M,j\le 2^{i-1}\)

解法&&个人感想

本题的代码实现难度比较大(不然怎么是绿题呢)
主要的思路是 因为整个完全二叉树的尺寸可以算出来
因此顶点的坐标是可以出来的 从顶点不断向下面两个方向递归建树
建完树后 我们已经有30分了 这个时候就要根据它的删点坐标进行删点
下面上代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int m,n,tem,len,h;
int dex[15],dey[15];
char tree[3105][3105];
int dis[12]={0,1,2,5,11,23,47,95,191,383,767,1535};
void draw(int x,int y,int t){
    if(t==m) return ;
    for(int i=1;i<=dis[m-t];i++){
        tree[x+i][y-i]='/';
        tree[x+i][y+i]='\\';//这个一定要双杠不然报错
    }
    tree[x+dis[m-t]+1][y+dis[m-t]+1]='o';
    tree[x+dis[m-t]+1][y-dis[m-t]-1]='o';
    draw(x+dis[m-t]+1,y-dis[m-t]-1,t+1);
    draw(x+dis[m-t]+1,y+dis[m-t]+1,t+1);
}//建树
int numx(int t){
    int ans=1;
    for(int i=m-1;i>=m-t+1;i--){
        ans+=dis[i];
    }
    ans+=t-1;
    return ans;
}//因为给出的删点是相对坐标 计算绝对坐标
int numy(int t,int y,int ans){
    if(t==1) return (len+1)/2-ans;
    if(y%2==0){
        return numy(t-1,y/2,ans-dis[m+1-t]-1);
    }
    if(y%2==1){
        return numy(t-1,(y+1)/2,ans+dis[m+1-t]+1);
    }
}//同理计算y方向的绝对坐标
void dele(int x,int y,int t){
    if(t==m) return ;
    for(int i=1;i<=dis[m-t];i++){
        tree[x+i][y+i]=' ';
        tree[x+i][y-i]=' ';
    } 
    tree[x+dis[m-t]+1][y+dis[m-t]+1]=' ';
    tree[x+dis[m-t]+1][y-dis[m-t]-1]=' ';
    dele(x+dis[m-t]+1,y+dis[m-t]+1,t+1);
    dele(x+dis[m-t]+1,y-dis[m-t]-1,t+1);
}//从要删的点往下删点
int main(){
    scanf("%d%d",&m,&n);
    if(n!=0){
        for(int i=1;i<=n;i++){
            scanf("%d%d",&dex[i],&dey[i]);
        }
    }
    for(int i=0;i<=2004;i++){
        for(int j=0;j<=2004;j++){
            tree[i][j]=' ';
        }
    }
    tem=1<<(m-1);
    len=3*tem-1;
    tree[1][(len+1)/2]='o';
    draw(1,(len+1)/2,1); 
    for(int i=1;i<=n;i++){
        int temx=numx(dex[i]);
        int temy=numy(dex[i],dey[i],0);
        tree[temx][temy]=' ';
        if(dey[i]%2==0){
            for(int j=1;j<=dis[m+1-dex[i]];j++){
                tree[temx-j][temy-j]=' ';
            }
        }
        if(dey[i]%2==1){
            for(int j=1;j<=dis[m+1-dex[i]];j++){
                tree[temx-j][temy+j]=' ';
            }
        }//这两个%2表示删掉上面点跟要删的点的连边
        dele(temx,temy,dex[i]);
    }
    for(int i=1;i<=m-1;i++){
        h+=dis[i];
    }
    h+=m;
    for(int i=1;i<=h;i++){
        for(int j=1;j<=len;j++){
            cout<<tree[i][j];
        }
        cout<<endl;
    }
    system("pause");
    return 0;
}//整体还是比较有难度的 主要是代码的细节部分
posted @ 2025-02-12 00:01  elainafan  阅读(43)  评论(0)    收藏  举报