【解题报告】POJ-1108 Split Windows
原题地址: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的更多相关文章
- POJ1108_Split Windows 解题报告
Split Windows 题目链接:http://poj.org/problem?id=1108 题目大意: 给你一棵二叉树的先序遍历,有三种字符:|.-.A~Z,然后用窗口表示出来,|: 表示将当 ...
- POJ 1001 解题报告 高精度大整数乘法模版
题目是POJ1001 Exponentiation 虽然是小数的幂 最终还是转化为大整数的乘法 这道题要考虑的边界情况比较多 做这道题的时候,我分析了 网上的两个解题报告,发现都有错误,说明OJ对于 ...
- POJ 2002 Squares 解题报告(哈希 开放寻址 & 链式)
经典好题. 题意是要我们找出所有的正方形.1000点,只有枚举咯. 如图,如果我们知道了正方形A,B的坐标,便可以推测出C,D两点的坐标.反之,遍历所有点作为A,B点,看C,D点是否存在.存在的话正方 ...
- Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告)
http://blog.csdn.net/geniusluzh/article/details/6619575 在说Tarjan算法解决桥和边双连通分量问题之前我们先来回顾一下Tarjan算法是如何 ...
- 【九度OJ】题目1108:堆栈的使用 解题报告
[九度OJ]题目1108:堆栈的使用 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1108 题目描述: 堆栈是一种基本的数据结构.堆 ...
- 【LeetCode】659. Split Array into Consecutive Subsequences 解题报告(Python)
[LeetCode]659. Split Array into Consecutive Subsequences 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id ...
- POJ 3126 Prime Path 解题报告(BFS & 双向BFS)
题目大意:给定一个4位素数,一个目标4位素数.每次变换一位,保证变换后依然是素数,求变换到目标素数的最小步数. 解题报告:直接用最短路. 枚举1000-10000所有素数,如果素数A交换一位可以得到素 ...
- poj分类解题报告索引
图论 图论解题报告索引 DFS poj1321 - 棋盘问题 poj1416 - Shredding Company poj2676 - Sudoku poj2488 - A Knight's Jou ...
- 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 ...
随机推荐
- 2014多校第六场 1005 || HDU 4925 Apple Tree
题目链接 题意 : 给你一块n×m的矩阵,每一个格子可以施肥或者是种苹果,种一颗苹果可以得到一个苹果,但是如果你在一个格子上施了肥,那么所有与该格子相邻(指上下左右)的有苹果树的地方最后得到的苹果是两 ...
- kafka配置
官网:http://kafka.apache.org/ 主要有3种安装方式: 1. 单机单broker 2. 单机多broker 3. 多机多broker 1. wget http://mirror. ...
- JS之DOM编程
为什么学dom编程? 通过dom编程,我们可以写出各种网页游戏 dom编程也是我们学习ajax技术的基础,所以我们必需掌握好dom编程. dom编程简介 DOM=Document Object Mo ...
- Tencent 的电话面试
Tencent的实习生招聘投了简历.然后,万万没想到昨晚腾讯IEG直接给我电话了.当时就惊呆了,我都没有找人内推,就直接电话面试了. 就为昨晚的电话面试写写感想吧!问的挺多的,基本上简历上写了的都问到 ...
- 【pku2115-C Looooops】拓展欧几里得-不定方程
http://poj.org/problem?id=2115 题解:一个变量从A开始加到B,每次加C并mod2^k,问加多少次.转化为不定方程:C*x+2^K*Y=B-A //poj2115 #inc ...
- Android安卓开发环境搭建详细教程
安装目录:步骤1 安装JDK步骤2 安装 Android SDK ----http://www.androiddevtools.cn/ 步骤3 安装Tomcat步骤4 安装Ant步骤5 安装Eclip ...
- lintcode :单词搜索
题目 单词搜索 给出一个二维的字母板和一个单词,寻找字母板网格中是否存在这个单词. 单词可以由按顺序的相邻单元的字母组成,其中相邻单元指的是水平或者垂直方向相邻.每个单元中的字母最多只能使用一次. 样 ...
- hdu 3537 Daizhenyang's Coin (翻硬币游戏)
#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; ]; i ...
- 8 Types Of Friends You Need To Have in Your Life
8 Types Of Friends You Need To Have in Your Life一生中应该有的8种类型的朋友Did you know that people without frien ...
- IOS开发-- NScoding 序列化
开篇 1到底这个序列化有啥作用? 面向对象的程序在运行的时候会创建一个复杂的对象图,经常要以二进制的方法序列化这个对象图,这个过程叫做Archiving. 二进制流可以通过网络或写入文件中(来源于某教 ...