模拟画图题P1185 绘制二叉树

2023-05-16

  可能更好的观看体验
  题目链接P1185 绘制二叉树

题意概述

  根据规则绘制一棵被删去部分节点的满二叉树。节点用 o o o 表示,树枝用/\表示。每一层树枝长度会变化,以满足叶子结点有如下特定:

  • 相邻叶子节点是兄弟节点(同一个父亲)时,间隔 3 3 3 个空格。
  • 相邻叶子节点不是兄弟节点,之间隔一个空格。

  一棵层数为 4 4 4 的满二叉树长这样(可能会出现因为字符宽度不一而出现偏移):

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

  删除节点的输入格式为:删除第 i i i 层从左往右数的第 j j j 个节点。注意删除时,把原有的字符用空格替换,结果是要打印空格的

分析

  又是一道画图模拟题,需要耐心分析。我采取的是找规律的方法,代码可能长,但是应该比较容易理解吧 Q A Q QAQ QAQ

  先看我们得维护什么信息才能实现初始化满二叉树和删点两个操作。初始化的方法有挺多,可以先铺好叶子结点,往上递归建树,也可以从根节点往下建树。但是有个问题是我们并不知道叶子结点到根节点的垂直距离,也不知道根节点的坐标。这时候我们就得找树枝的规律了。建好树后我们要删点,但是输入点的方式不能直接确定点的坐标,得找同一层节点分布的规律。为了后续讨论方便,我们约定叶子节点为第一层,根节点在第 m m m

树枝的规律

  打表加看图硬分析(这里的树枝长定义为连接第 i i i 层节点与第 i + 1 i+1 i+1 层节点的树枝长):

层数 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5
树枝长 l e n len len 1 1 1 2 2 2 5 5 5 11 11 11 23 23 23
规律 1 1 1 1 + ( 2 − 1 ) 1+(2-1) 1+(21) ( 1 + 2 ) + ( 3 − 1 ) (1+2)+(3-1) (1+2)+(31) ( 1 + 2 + 5 ) + ( 4 − 1 ) (1+2+5)+(4-1) (1+2+5)+(41) ( 1 + 2 + 5 + 11 ) + ( 5 − 1 ) (1+2+5+11)+(5-1) (1+2+5+11)+(51)

图表如果炸了可以到我的博客上看

  可以看出,对于第 i ( 2 ≤ i ) i(2 \leq i ) i(2i) 层的树枝长,其实是等于前 i − 1 i-1 i1 层树枝的长度之和与 i − 1 i-1 i1 的和的。看图更容易发现这一规律:

  这里第 3 3 3 层的树枝和前两层的树枝和节点有一一对应的关系(红色实线),可以看出长度恰好就是前两层节点数2加上前两层的树枝长度, O ( n ) O(n) O(n) 递推可以得到树枝长度数组,记为 l e n len len

同层节点规律

  观察可知除了第一层外的其他层的同层相邻节点距离是一定的。所以确定每一层第一个节点的位置就可以推出其他节点的位置了。

  让第一层第一个节点水平位置为 1 1 1 。再次观察前面的图,可以发现 i i i 层第一个节点的水平位置其实就是 l e n i + 1 len_i+1 leni+1 。所以根据前面推出来的树枝长数组可以推出。竖直位置就得从根节点(也就是第 m m m 层)往下推了,根节点竖直位置为 1 1 1 i i i 层竖直位置就其实就是 = = = i + 1 i+1 i+1 层竖直位置 + + + i i i 层的树枝长度 + 1 +1 +1 ,也是比较明显的。我代码中将两个方向的位置分别用 p o s pos pos h h h 表示了。以下是初始化函数和一些数组定义:

const int N = 3100;
int len[20],m,n,pos[20],h[20];
char a[N][N];  //满二叉树数组,注意开大一点
void prepare(){
    int sum = 1;            //记录树枝长的前缀和
    len[1] = 1;pos[1] = 1;  //第一层树枝长为1,第一个节点水平位置为1
    FOR(i,2,m) {
        len[i] = sum + i-1; //递推式子
        sum += len[i];
        pos[i] = len[i] + 1;//顺便得到第i层第一个节点的水平位置
    }
    h[m] = 1;
    for(int i = m-1; i ;i --) h[i] = h[i+1]+len[i]+1;//得到第i层的竖直位置
    memset(a,' ',sizeof(a)); //全都铺满空格
}

  第一层节点的分布已在题目中确定了,相邻节点是兄弟就隔 3 3 3 个,不是隔 1 1 1 个,因为与其他层分布不同,是要特判的。其他层结点间距也是很好找到规律的,就是 2 × l e n i + 1 2 \times len_i+1 2×leni+1 。至此,我们这棵树的信息基本完备了,下面就是比较轻松的绘制和删点了。

绘制和删点

  这两个操作都是递归进行的。

  因为我们已经知道了每一层的树枝长度,所以我们可以从根节点开始建树,递归左右子树即可。注意我们定义的树枝长度为连接第 i i i 层节点与第 i + 1 i+1 i+1 层节点的树枝长度。代码采用了前序遍历的方式:

void draw(int x,int y,int depth){
    a[x][y] = 'o'; //画节点
    if(depth == 1) return;  //到叶子节点了,返回
    //开始画树枝,lx,ly定位左树枝,rx,ry定位右树枝
    int lx = x+1,ly = y-1,rx = x+1,ry = y+1;
    FOR(i,1,len[depth-1]){//注意画的树枝长度为下一层的树枝长度
        a[lx][ly] = '/';
        a[rx][ry] = '\\';
        lx = lx+1,ly = ly-1,rx = rx+1,ry = ry+1;
    }
    draw(lx,ly,depth-1);   //画下一层节点
    draw(rx,ry,depth-1);
}

  删点比较暴力,注意删点要同时删除与父亲节点的联系和与孩子节点的联系:

void destroy(int x,int y){
    a[x][y] = ' ';           //将该点置为空格
    if(a[x-1][y-1] == '\\') destroy(x-1,y-1);         //左上角
    if(a[x-1][y+1] == '/')  destroy(x-1,y+1);         //右上角
    if(a[x+1][y-1] == '/' || a[x+1][y-1] == 'o') destroy(x+1,y-1); //左下角,因为往下还要删除孩子节点,要多一个判断
    if(a[x+1][y+1] == '\\'|| a[x+1][y+1] == 'o') destroy(x+1,y+1); //右下角同理
}

一些可能阻止你AC的坑

  • 数组大小要开大一点。满二叉树最大层数为 10 10 10 ,叶子结点的竖直为置最大为 768 768 768,该层宽度为 3072 3072 3072 。所以数组大小应至少开到 769 ∗ 3073 769*3073 7693073 。否则可能出现 T o o   l o n g   o n   l i n e   1 . \mathbf{Too~ long~ on~ line~ 1}. Too long on line 1. 或者直接 R E \mathbf{RE} RE 等错误。
  • 数组定义比较多,要用一些比较清晰的变量名,并且时刻记得它们的意义。
  • 10 10 10 个点有点玄学。如果用快读会 T L E \mathbf{TLE} TLE 掉,因为数据量小,全都用 c i n \mathbf{cin} cin 就可以过了。

C o d e : Code: Code:

#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int N = 3100;
int len[20],m,n,pos[20],h[20];
char a[N][N];  //满二叉树数组,注意开大一点
int read(){int sum = 0,fu = 1;char ch = getchar();while(!isdigit(ch)){if(ch == '-')fu = -1;ch = getchar();}while (isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch = getchar();}return sum*fu;}
//预处理
void prepare(){
    int sum = 1;            //记录树枝长的前缀和
    len[1] = 1;pos[1] = 1;  //第一层树枝长为1,第一个节点水平位置为1
    FOR(i,2,m) {
        len[i] = sum + i-1; //递推式子
        sum += len[i];
        pos[i] = len[i] + 1;//顺便得到第i层第一个节点的水平位置
    }
    h[m] = 1;
    for(int i = m-1; i ;i --) h[i] = h[i+1]+len[i]+1;//得到第i层的竖直位置
    memset(a,' ',sizeof(a)); //全都铺满空格
}

//绘制
void draw(int x,int y,int depth){
    a[x][y] = 'o'; //画节点
    if(depth == 1) return;  //到叶子节点了,返回
    //开始画树枝,lx,ly定位左树枝,rx,ry定位右树枝
    int lx = x+1,ly = y-1,rx = x+1,ry = y+1;
    FOR(i,1,len[depth-1]){ //注意画的树枝长度为下一层的树枝长度
        a[lx][ly] = '/';
        a[rx][ry] = '\\';
        lx = lx+1,ly = ly-1,rx = rx+1,ry = ry+1;
    }
    draw(lx,ly,depth-1);   //画下一层节点
    draw(rx,ry,depth-1);
}

//删点
void destroy(int x,int y){
    a[x][y] = ' ';           //将该点置为空格
    if(a[x-1][y-1] == '\\') destroy(x-1,y-1);         //左上角
    if(a[x-1][y+1] == '/') destroy(x-1,y+1);          //右上角
    if(a[x+1][y-1] == '/' || a[x+1][y-1] == 'o') destroy(x+1,y-1); //左下角,因为往下还要删除孩子节点,要多一个判断
    if(a[x+1][y+1] == '\\'|| a[x+1][y+1] == 'o') destroy(x+1,y+1); //右下角同理
}

//打印
void print(){
    int height = h[1];          //第一层的竖直位置
    int width = 6 * (1<<(m-1)); //第一层的宽度(最宽)
    FOR(i,1,height){
        FOR(j,1,width)
            printf("%c",a[i][j]);
        printf("\n");
    }
}

signed main(){
    m = read();n = read();
    prepare();
    draw(1,pos[m],m); //(1,pos[m])为根节点坐标,位于第m层
    while(n--){
        int i = read(),j = read();
        if(i > 10) continue;
        int x = h[m+1-i],y; //因为层的定义与题目不同,得转化一下
        //分第一层和其他层两种情况计算水平位置y
        if(i == m){
            if(j & 1) y = pos[1] + j/2*6;
            else y = pos[1] + j/2*6 - 2;
        }
        else y = pos[m+1-i] + (j-1)* (2 * len[m+1-i] + 2); //可以手推
        destroy(x,y);
    }
    print();
    return 0;
}

 如果你想练习一下类似的画图题,以下两题可以做做看:

  • P1498 南蛮图腾
  • P1058 立体图
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

模拟画图题P1185 绘制二叉树 的相关文章

  • edm经验1

    edm经验 xff1a 1 lt table border 61 34 0 34 height 61 34 100 34 cellpadding 61 34 0 34 cellspacing 61 34 0 34 style 61 34 b
  • hive2.0.0安装(配合hadoop2.6.0)

    一 前提条件 安装了Hadoop2 6 0 xff0c 并且配置了相关环境变量 jdk安装 xff0c 免密登录设置 xff0c 环境变量设置 JAVA HOME JRE HOME CLASSPATH PATH 二 安装配置 1 下载hiv
  • mysql删除无主键表中重复记录(只保留一条记录)

    考虑多条语句变通的办法 mysql gt span class hljs operator span class hljs keyword select span span class hljs keyword from span x us
  • redhat7安装openstack(juno版/附所需文件)

    这种方式使用自己制作的yum源安装openstack allinone xff0c 基本一装一个准 xff0c 不会出差错 xff0c 适合初学者安装 一 使用vmware安装redhat7操作系统 百度盘地址https pan baidu
  • win7部署kafka_2.11

    kafka作为开源的分布式消息通信框架 xff0c 可以在有jvm的机器上部署 运行 这里介绍在windows7上的部署 kafka内部自带了zookeeper 如果单机简单部署 xff0c 可以不用另外下载部署zookeeper 1 下载
  • 正则表达式驼峰转中(下)划线

    一 驼峰转中划线采用正则来实现可以看如下代码 xff1a span class hljs string 34 marginTop 34 span replace a z A Z span class hljs string 34 span
  • 工作无聊?程序员上班没事做该怎么办!

    作为一名程序员 xff0c 工作强度不稳定是比较正常的 xff0c 忙的时候会埋怨 xff0c 闲的时候会发慌 合理的安排自己的工作也是程序员最基本且最重要的能力 工作不紧张的时候 xff0c 可以好好利用起来充实自己 xff0c 根据自身
  • mysql5.7.x:this is incompatible with DISTINCT

    DISTINCT关键字经常在MySQL中使用 xff0c 在mysql5 7以前的版本中一般没有什么问题 xff0c 但是在5 7以后的版本中会遇到这样的错误 Caused by java sql SQLException Expressi
  • sublime3配置Python编译器快速编译python程序

    本文介绍经常用的sublime编辑器作为PythonIDE时如何快速编译代码并得到执行结果 xff0c 前提是本机已经安装了python xff0c 并加入了环境变量 xff0c 命令行下输入python xff0c 会有如下输出 xff1
  • redhat7通过yum安装mysql5.7.17

    rhel centos系列linux操作系统自身没有mysql的源 xff0c 需要自行下载安装 本文介绍如何安装mysql5 7 x数据库 第一步 xff1a 下载源 root span class hljs variable 64 cl
  • mysql主从复制环境搭建

    所需服务器 xff1a 两台 centos7 linux虚拟机 服务器分配 server 192 168 56 201 client 192 168 56 202 说明 xff1a 使用server做主库服务器client做从库服务器 第一
  • hadoop2.6.0伪分布式环境搭建

    Hadoop作为分布式大数据处理框架在数据处理应用中有广泛的应用 xff0c 本文介绍在Linux环境下搭建hadoop伪分布式集群 xff0c 记录下自己的学习过程 一 虚拟机准备 xff0c 为了减少折腾 xff0c 不建议在windo
  • ubuntu1404单机安装部署openstack-juno

    Redhat上可以很快的使用All in one的方式安装openstack xff0c 先安装packstack 然后通过packstack allinone这条命令 就可以一步安装openstack 最后设置IP和网桥 xff0c 就可
  • ubuntu上利用qemu-kvm创建虚拟机

    kvm是Kernel based Virtual Machine的缩写 xff0c 即基于内核的虚拟机技术 xff0c 运行在具备Intel vt或者AMD V功能的x86平台上 在linux2 6 20之后的版本中kvm成为了linux内
  • Fatal error in launcher: Unable to create process using解决办法

    我的机器是windows7 64位机器 xff0c 本来默认安装了pip命令是9 0 1版本的 xff0c 网上有介绍说可以安装1 5 6版本 我考虑将pip更改为1 5 6版本 xff0c 去官网下载一个whl的文件 xff0c 利用pi
  • openstack-install-ubuntu-single说明

    ubuntu1404单机安装部署openstack juno值得注意的地方 xff0c 这里说明一下 先来说说openstack组件 keystone gt 认证组件glance gt 镜像组件 xff0c 负责管理虚拟机镜像nova gt
  • hive自定义函数UDF

    Hive自定义函数 UDF xff0c 可以帮助用户轻松实现在hql语句中展现自定义查询结果 这里以一个简单的连接函数来实现用户自定义函数 xff0c 假设表结构如下 xff1a 表中只有两个简单的字段 xff0c id和name 这里实现
  • Oracle 数据误删的恢复措施

    Oracle中 常见的数据删除操作就三种 xff0c truncate xff0c drop xff0c delete xff0c 下面分类说一下如何恢复 Truncate xff1a 该操作执行后 xff0c 保留表结构 xff0c 清空
  • Hive使用入门

    先介绍一些基本的命令 xff1a 1 进入hive命令行 xff0c 这种方式进入之后 xff0c 操作结果展示时带有执行mapreduce的调试信息 xff1b hive service cli 等同于直接输入hive 2 进入hive命
  • Hive内部表和外部表的区别

    hive作为基于hdfs的数据仓库 xff0c 在构建表的时候 xff0c 会有内部表和外部表 xff0c 这里介绍两者的异同点 相同点 xff1a 1 他们都是用mysql或者derby作为元数据存储 xff0c 他们在元数据的组织上是相

随机推荐

  • hive:For direct MetaStore DB connections, we don't support retries at the client level

    hive创建表和导入数据都没有问题 xff0c 在删除表 xff0c 做drop table 时报如题所示的错误 有的文章说修改元数据库字符集为latin1 但是元数据库字符集默认创建就是latin1 修改字符集无法解决该问题 通过更换my
  • rhel7安装docker

    docker是当下最流行的虚拟化容器技术之一 xff0c 它是基于lxc的一种容器技术 xff0c 该技术已经非常成熟 xff0c 而且在实际应用中已经越来越普遍 很多框架都有对docker的支持 xff0c 包括hadoop spark
  • Openstack使用ubuntu镜像启动虚拟机实例

    一般情况下openstack环境搭建好了之后 xff0c 就是测试启动虚拟机 通常我们会使用一个最基本的镜像cirros 0 3 3 x86 64 disk img来作为镜 像 xff0c 使用glance命令行或者horizon的图形化界
  • docker使用Dockerfile构建镜像

    docker获取镜像 xff0c 除了docker pull docker load之外还可以通过自定义Dockerfile的方式通过命令docker build 来构建新镜像 通过这种方式可以很自由的定义想要安装的镜像 xff0c 想要安
  • django环境搭建

    django是python开发框架 xff0c 是一个丰富的web框架 第一步 xff1a 安装pip wget https bootstrap pypa io get pip py python get pip py 第二步 xff1a
  • docker配置国内仓库镜像registry-mirror

    Docker在默认安装之后 xff0c 当需要下载镜像时 xff0c 通过命令docker pull learn tutoral拉取示例镜像 xff0c 或者其他镜像时 xff0c 都是访问默认的docker hub上的镜像 xff0c 在
  • TypeError: object() takes no parameters

    python面向对象编程第一个坑 TypeError object takes no parameters 出现这个错误 xff0c 一般就是构造函数 init 书写的不对 xff0c 检查一下是否是少了一个下划线或者是少写了一个i字母 x
  • windows上Flask环境搭建

    Flask是python开发框架 用来快速构建web项目 下面介绍如何在windows上搭建flask开发环境并运行一个demo 第一步 创建项目并构建flask环境 mkdir flaskapp cd flaskapp virtualen
  • WebSocket 测试工具

    一 WebSocket 简介 WebSocket是一种在单个TCP连接上进行全双工通信的协议 WebSocket使得客户端和服务器之间的数据交换变得更加简单 xff0c 允许服务端主动向客户端推送数据 在WebSocket API中 xff
  • 利用pipework为docker容器设置固定IP

    今天介绍如何在redhat centos7系列机器上使用pipework为docker启动的容器指定一个固定ip 我们知道默认情况下 xff0c docker会使用bridge网络模式为每一个启动的容器动态分配一个IP xff0c 以172
  • 用docker玩坏ubuntu虚拟机容器

    当我们装上docker之后 xff0c 自然会pull一个或多个镜像玩玩 xff0c 这时候 xff0c docker hub仓库上有很多系列操作系统镜像 xff0c 每个系列又有很多不同功能的虚拟机镜像 xff0c 比如centos分6还
  • tornado入门实例

    tornado是python web开发的又一个轻量级框架 tornado框架需要安装 xff0c 为了方便 xff0c 我直接安装了Anaconda 2 4 1 里面直接就带了tornado 还有很多python库 numpy scipy
  • web.py框架入门

    web py是python web开发的一个轻量级框架 web py可以通过pip命令安装 xff0c pip install web py 编写官网示例代码 xff1a vi index py import web urls 61 34
  • graphviz快速上手

    graphviz最初是AT amp T实验室用来画流程图的工具 xff0c 使用dot语言 其中根据图的类型可以分为有向图 dirgraph 和无向图 graph 我们知道图是由点 node 和边 edge 组成的 xff0c 在有向图中边
  • mysqld: File './mysql-bin.index' not found (Errcode: 13 - Permission denied)

    我们通过yum方式安装mysql 会生成mysql mysql用户组和用户 xff0c 启动mysql默认是使用mysql用户 如果我们开启了慢log日志 xff0c 而且我们使用service mysqld start启动mysql 会报
  • redhat7编译安装php-5.5.38

    1 从官网下载php源码包 php 5 5 38 2 安装依赖包 yum install libxml2 libxml2 devel bzip2 devel libcurl devel y yum install openssl opens
  • spark-1.6.0源码编译安装

    环境准备 spark是scala语言写的 xff0c scala运行需要jdk 如果通过maven编译 xff0c 还需要maven环境 xff0c 因此spark源码编译需要安装jdk scala apache maven这三样环境 这里
  • ZendStudio+php+Apache开发环境搭建

    学习php xff0c 我们就想有一个好的ide xff0c ZendStudio是专门为php开发提供的ide xff0c 写完代码立马能够在工作空间中调试 xff0c 可以通过Run As gt PHP CLI Application
  • 图文详解win7实现局域网共享文件

    工作中 xff0c 我们有时候会拥有两台机器 xff0c 避免机器之间文件传来传去 xff0c 可以使用局域网文件共享 xff0c 在一台机器上开启文件共享 xff0c 另一台机器通过IP访问 xff0c 即可轻松实现文件互访 今天介绍我们
  • 模拟画图题P1185 绘制二叉树

    可能更好的观看体验 题目链接P1185 绘制二叉树 题意概述 根据规则绘制一棵被删去部分节点的满二叉树 节点用 o o o 表示 xff0c 树枝用 表示 每一层树枝长度会变化 xff0c 以满足叶子结点有如下特定 xff1a 相邻叶子节点