【解题报告】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 ...
随机推荐
- php获取网页header信息的4种方法
php获取网页header信息的方法多种多样,就php语言来说,我知道的方法有4种, 下面逐一献上. 方法一:使用get_headers()函数 推荐指数: ★★★★★ get_header方法最简单 ...
- (转)android ListView详解
转自: http://www.cnblogs.com/allin/archive/2010/05/11/1732200.html 在android开发中ListView是比较常用的组件,它以列表的形 ...
- 国内银行CNAPS CODE 查询 苹果开发者,应用内购,需要填写税务相关信息必须的
https://e.czbank.com/CORPORBANK/QYUK http://weekend.blog.163.com/blog/static/746895820127961346724/
- 关于HTTP协议的学习
HTTP(HyperTextTransferProtocol)是超文本传输协议的缩写,它用于传送WWW方式的数据,关于HTTP 协议的详细内容请参考RFC2616.HTTP协议采用了请求/响应模型.客 ...
- 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 ...
- Redis的String操作
set key value [ex 秒数] / [px 毫秒数] [nx] /[xx] 如: set a 1 ex 10 , 10秒有效 Set a 1 px 9000 , 9秒有效 注: 如果ex, ...
- Grunt :任务自动管理工具
来自<JavaScript 标准参考教程(alpha)>,by 阮一峰 在Javascript的开发过程中,经常会遇到一些重复性的任务,比如合并文件.压缩代码.检查语法错误.将Sass代码 ...
- svn执行clean up命令时报错或被锁定的解决方法
用SVN经常出现被锁定而无法提交的问题,选择解锁又提示没有文件被锁定,很是头疼.这里整理了一下SVN 被锁定的几种解决方法: 1.出现这个问题后使用“清理”即"Clean up"功 ...
- Android 的 init.rc 文件简介【转】
转自:http://blog.csdn.net/yimiyangguang1314/article/details/6268177 init.rc由许多的Action和Service组成.每一个语句占 ...
- hdu - 1010 Tempter of the Bone (dfs+奇偶性剪枝) && hdu-1015 Safecracker(简单搜索)
http://acm.hdu.edu.cn/showproblem.php?pid=1010 这题就是问能不能在t时刻走到门口,不能用bfs的原因大概是可能不一定是最短路路径吧. 但是这题要过除了细心 ...