原题地址:http://poj.org/problem?id=1108

==============================

题目大意:

一棵树表示一个窗口,它的叶子节点都是大写字母,非叶子节点是两种字符‘|’和‘-’,表示它的两棵子树分别位于主窗口的上下和左右。给你一棵树,要求画出窗口。

1.每个叶子结点用一个字母表示,对应图中最小的一个窗口,该窗口的左上角写的是这个字母,其他三个角是*号,但如果这个角是其他窗口的左上角,则要显示对应的字母。窗口的上下边用字符‘-’表示,左右边用字符‘|’表示。

2.可以知道,一个大窗口如果被分为上下两个部分,则上下两个小窗口的宽度是相同的,若被分为左右两个窗口,则高度是相同的。而单独一个小窗口应该是2*2的大小,但如果两部分窗口的宽度(或高度)不能相同,则较小的那个窗口要按比例拉伸且左边的(或上边的)窗口计算出来的大小为小数时,要向上取整。

题目输入时是按照先序遍历的方式输入的。

==============================

解题思路:

思路分为两步:

1、先分别计算出每个子窗口最小的大小(高和宽),按后序遍历的方式,如果是叶子节点,则高和宽都是2,若是‘-’窗口,则该窗口的高等于上窗口加下窗口,宽等于两个窗口的高的较大值。若是‘|’同理。按这样的方式计算出来的长宽不是最终的高宽,但最大的那个窗口的窗口的高和宽就是整个图形的高和宽了。

2、根据各个窗口的高和宽,在一个字符数组里逐条画出分隔窗口每条线(先序遍历)。在计算线的位置的时候要按比例计算出每部分窗口的实际宽度和高度。

==============================

解题过程:

1、数据结构:

 #define N 2000
struct NODE
{
char c;//保存窗口的字母或者‘-’和‘|’
int k;//窗口的宽度
int h;//窗口的高度
int l,r;//左孩子和右孩子的数组下标
};
NODE node[N];//保存整个二叉树
char ans[N][N];//保存最终的图形

本来想用数组存二叉树的时候,第i个节点的左孩子用第i*2个节点表示,第2*i+1个节点表示右孩子,但做下去RE了,原因是这个二叉树不是完全二叉树,若所有的节点都只有左孩子,则要用到2^36,则必然放不下,因此改成l,r分别表示该节点的左孩子和右孩子的数组下标。

2、二叉树的输入:

由于该二叉树的输入是按先序遍历的方式,而每个叶子节点都是大写字母,因此,在输入的时候用先序遍历的方式,逐个读取字符,若是叶子节点则返回,若不是,则继续读入左孩子和右孩子。

 int k;
int chuli()//输入
{
scanf("%c",&node[k].c);
int n=k;
if(node[n].c=='|'||node[n].c=='-')
{
++k;
node[n].l=k;
chuli();
++k;
node[n].r=k;
chuli();
}
else return ;
}

用k作为全局变量,使输入的树的结点按顺序存储在数组中。

3、计算每个窗口的大小:

 int f(int n)//计算每个窗口的大小
{
if(node[n].c<='Z'&&node[n].c>='A')
{
node[n].k=node[n].h=;
return ;
}
f(node[n].l);
f(node[n].r);
if(node[n].c=='|')
{
node[n].k=node[node[n].l].k+node[node[n].r].k;
node[n].h=MAX(node[node[n].l].h,node[node[n].r].h);
}
else
{
node[n].k=MAX(node[node[n].l].k,node[node[n].r].k);
node[n].h=node[node[n].l].h+node[node[n].r].h;
}
return ;
}

后序遍历整个二叉树,如果是叶子节点,则高和宽都是2,若是‘-’窗口,则该窗口的高等于上窗口加下窗口,宽等于两个窗口的高的较大值。

4、根据计算好的每个窗口的大小在字符的二维数组ans里画出整个窗口:
初始化为一个高度为node[1].h,宽度为node[1].k的窗口,四个角都用‘*’表示。

 //画外框
ans[][]='*';
for(j=;j<node[].k;j++) ans[][j]='-';
ans[][j]='*';
for(i=;i<node[].h;i++)
{
ans[i][]='|';
for(j=;j<node[].k;j++) ans[i][j]=' ';
ans[i][j]='|';
}
ans[i][]='*';
for(j=;j<node[].k;j++) ans[i][j]='-';
ans[i][j]='*';

画每条线和填入字母:

 void pr1(int x,int y,int l)//画竖线,以点(x,y)为上端点,画一条长为l的线,其中,两个端点用‘*’表示。
{
int i;
ans[x][y]='*';
for(i=;i<l;i++)
{
ans[x+i][y]='|';
}
ans[x+i][y]='*';
}
void pr2(int x,int y,int l)//画横线
{
int i;
ans[x][y]='*';
for(i=;i<l;i++)
{
ans[x][y+i]='-';
}
ans[x][y+i]='*';
}
int p(int x,int y,int i)//(x,y)表示当前窗口的左上角的坐标,i表示当前节点的数组下标。
{
//p1();
//getchar();
if(node[i].c=='|')
{
node[node[i].l].h=node[node[i].r].h=node[i].h;
node[node[i].r].k=node[i].k*node[node[i].r].k/(node[node[i].r].k+node[node[i].l].k);
node[node[i].l].k=node[i].k-node[node[i].r].k;//按比例分配宽度
//画竖线
pr1(x,y+node[node[i].l].k,node[i].h);
p(x,y,node[i].l);
p(x,y+node[node[i].l].k,node[i].r);
}
else if(node[i].c=='-')
{
node[node[i].l].k=node[node[i].r].k=node[i].k;
node[node[i].r].h=node[i].h*node[node[i].r].h/(node[node[i].r].h+node[node[i].l].h);
node[node[i].l].h=node[i].h-node[node[i].r].h;//按比例分配高度
//画横线
pr2(x+node[node[i].l].h,y,node[i].k);
p(x,y,node[i].l);
p(x+node[node[i].l].h,y,node[i].r);
}
else
{
ans[x][y]=node[i].c;//在窗口左上角填入字母
}
return ;
}

在按比例计算宽度和高度的时候,由于要将第一部分的宽度和高度向上取整,也可以先计算右子树的宽度或高度,再用总宽度或高度减去它计算出左子树的宽度或高度。

5、输出最后的图形:

 void p1()//输出窗口
{
int i,j;
for(i=;i<=node[].h;i++)
{
for(j=;j<=node[].k;j++)
{
printf("%c",ans[i][j]);
}
printf("\n");
}
}

6、主函数:

 #include<stdio.h>
#include<iostream>
#define N 2000
#define MAX(x,y) (((x)>(y))?(x):(y))
using namespace std;
int main()
{
int t,i,j,cas=;
cin>>t;
while(t--)
{
getchar();
k=;
chuli();//输入
//cout<<"!!"<<endl;
f();//计算窗口大小
//画外框
ans[][]='*';
for(j=;j<node[].k;j++) ans[][j]='-';
ans[][j]='*';
for(i=;i<node[].h;i++)
{
ans[i][]='|';
for(j=;j<node[].k;j++) ans[i][j]=' ';
ans[i][j]='|';
}
ans[i][]='*';
for(j=;j<node[].k;j++) ans[i][j]='-';
ans[i][j]='*';
cout<<cas++<<endl;
p(,,);//处理整个框
p1();//输出
}
}

【解题报告】POJ-1108 Split Windows的更多相关文章

  1. POJ1108_Split Windows 解题报告

    Split Windows 题目链接:http://poj.org/problem?id=1108 题目大意: 给你一棵二叉树的先序遍历,有三种字符:|.-.A~Z,然后用窗口表示出来,|: 表示将当 ...

  2. POJ 1001 解题报告 高精度大整数乘法模版

    题目是POJ1001 Exponentiation  虽然是小数的幂 最终还是转化为大整数的乘法 这道题要考虑的边界情况比较多 做这道题的时候,我分析了 网上的两个解题报告,发现都有错误,说明OJ对于 ...

  3. POJ 2002 Squares 解题报告(哈希 开放寻址 & 链式)

    经典好题. 题意是要我们找出所有的正方形.1000点,只有枚举咯. 如图,如果我们知道了正方形A,B的坐标,便可以推测出C,D两点的坐标.反之,遍历所有点作为A,B点,看C,D点是否存在.存在的话正方 ...

  4. Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告)

     http://blog.csdn.net/geniusluzh/article/details/6619575 在说Tarjan算法解决桥和边双连通分量问题之前我们先来回顾一下Tarjan算法是如何 ...

  5. 【九度OJ】题目1108:堆栈的使用 解题报告

    [九度OJ]题目1108:堆栈的使用 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1108 题目描述: 堆栈是一种基本的数据结构.堆 ...

  6. 【LeetCode】659. Split Array into Consecutive Subsequences 解题报告(Python)

    [LeetCode]659. Split Array into Consecutive Subsequences 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id ...

  7. POJ 3126 Prime Path 解题报告(BFS & 双向BFS)

    题目大意:给定一个4位素数,一个目标4位素数.每次变换一位,保证变换后依然是素数,求变换到目标素数的最小步数. 解题报告:直接用最短路. 枚举1000-10000所有素数,如果素数A交换一位可以得到素 ...

  8. poj分类解题报告索引

    图论 图论解题报告索引 DFS poj1321 - 棋盘问题 poj1416 - Shredding Company poj2676 - Sudoku poj2488 - A Knight's Jou ...

  9. POJ 2054 Color a Tree解题报告

    题干 Bob is very interested in the data structure of a tree. A tree is a directed graph in which a spe ...

随机推荐

  1. IDA 与VC 加载符号表

    将Windbg路径下的symsrv.yes 拷贝到ida 的安装目录,重新分析ntoskrnl.exe, 加载本地的符号表 添加环境变量  变量名:_NT_SYMBOL_PATH变量值:SRV*{$P ...

  2. ubuntu为Python添加默认搜索路径

    我们在自己写python模块的时候,怎么样把自己写的模块加入到python默认就有的搜索路径中呢?不要每次非得import sys; sys.path.append(‘/home/uestc/rese ...

  3. ios开发多线程--GCD

    引言 虽然GCD使用很广,而且在面试时也经常问与GCD相关的问题,但是我相信深入理解关于GCD知识的人肯定不多,大部分都是人云亦云,只是使用过GCD完成一些很简单的功能.当然,使用GCD完成一些简单的 ...

  4. java--vo

    VO是跟数据库里表的映射,一个表对应一个VO DAO是用VO来访问真实的表,对数据库的操作都在DAO中完成 BO是业务层,做逻辑处理的 VO , PO , BO , QO, DAO ,POJO, O/ ...

  5. 用PostGreSQL实现三层(复习)

    modal DAL,BLL都是类库的形式 最终结果如下: 数据库代码: -- Table: student -- DROP TABLE student; CREATE TABLE student ( ...

  6. hadoop 1.2.1 eclipse 插件编译

    hadoop-1.2.1 eclipse插件编译       在ubuntu上进行hadoop相关的开发,需要在eclipse上安装hadoop开发插件.最新释放出的hadoop包含源码的包,以had ...

  7. 【算法题】- 求和等于K子数组

    一整数(有正有负)数组,用尽量少的时间计算数组中和为某个整数的所有子数组 public class SumK { public static void main(String[] args) { in ...

  8. 浅析CSS负边距

    本文主要讨论两点,1.左右负边距对元素宽度的影响:2.负边距对浮动元素的影响. 在讨论这两点前,首先要理解盒模型.文档流. 盒模型,见下图,简单明了. 文档流,将窗体自上而下分成一行行, 并在每行中按 ...

  9. MYSQL数据库错误代码提示汇总

    Mysql出错代码表 1005:创建表失败 1006:创建数据库失败 1007:数据库已存在,创建数据库失败 1008:数据库不存在,删除数据库失败 1009:不能删除数据库文件导致删除数据库失败 1 ...

  10. C#服务启动以及服务指令

    Windows系统中使用 cmd 命令安装和卸载服务方法如下: 第一种方法: 1. 开始->运行->cmd 2. cd到C:\WINDOWS\Microsoft.NET\Framework ...