ZOJ: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1043
POJ: http://poj.org/problem?id=1108
题目大意:(图见原题)
每一个无分割的窗口有一个大写字母标签。每个窗口左上角有大写字母标签,其他三个角有*号,上下边界用-,左右边界用|表示。
每个窗口分割可以用一颗二叉树表示,表示方式如下:
1、无分割的窗口用大写字母表示
2、有再分的窗口对应的二叉树根为-(横分割)或者|(竖分割),左右子树分别是上下或者左右子窗口
二叉树用先序遍历的方式描述。
每个为分割的窗口里头必须有至少放一个字母的空间存在,所以每一种窗口分割情况都有对应的最小窗口大小。
考虑Tree4和Window4。主窗口分为左右两边,分别是Tree2和Tree3。左窗口和Window2一致,右边窗口的高度拉伸至与左边一致。窗口的拉伸规则取决于如何定义窗口的尺寸。尺寸计算时很容易想象窗口包含其内部和每个边界上半个字符的大小,所以整个窗口的尺寸比内部大小多一个单位。所以最小的窗口尺寸是2*2,1个单位是内部,1个单位是边界引入的尺寸增加。从这个定义可以知道一个窗口的宽度是左右子窗口宽度之和,高度是上下子窗口的高度和。
Window4的右窗口需要拉伸至高度为10。右窗口分为上子窗口P(最小高度2)和下子串口|Q|RST(最小高度4)。窗口的拉伸规则:如果可能的话,拉伸后各子窗口的高度与其最小高度成比例。例如此窗口需要拉伸到高度D=10,我们需要决定上下子窗口的高度D1和D2。最小总高度d=6,上下子窗口最小高度d1=2,d2=4。D1 = d1*(D/d) = 2*(10/6) = 3.333...and D2 = d2*(D/d) = 6.666....结果调整成整数为4和6。
类似地,可以计算 -|Q|RST这个窗口。这个窗口又分为上下两部分,分别为|Q|RS和T,它们的最小高度d1=d2=2。高度要拉伸至D=6,所以D1 = D2 = 2*(6/4) = 3 (正好是整数)。
窗口的总体积总是在子窗口体积之前决定的。在这个例子中,只有高度需要分配。但是如果水平和垂直的分割是相互交叉的,例如最后一个样例,那么宽度也需要分配。如果分配计算时得到的结果不是整数,让上面的子窗口或者左边子窗口的尺寸取计算结果的上整。
输入:
第一行为数据规模,整数。之后每一行是窗口对应二叉树的先序遍历,只包含|,-和26个大写字母。
输出:
最每组数据输出编号和窗口。
解题思路:
从叶子开始建立窗口,从下往上合并、拉伸。
最早的思路是每次建立的时候就用字符串把窗口的表示存储下来,但是这样由于拉伸操作是递归的,需要对二叉树每个叶子节点都存放窗口的字符表示,要占用很大的空间,且拉伸操作的时候处理字符串也很麻烦。
然后想到其实只要对二叉树每个结点存储一下对应窗口的长和宽就可以了,再存储一下分割状态:UP(UpDown, define as -1), LR(LeftRight, define as -2)和字母(不再分割的话这个小窗口有对应的字母标签)
数据结构:
typedef struct node { int w, h; //width height int type; //split type int lson, rson; }node;
先递归计算窗口的大小和每个子窗口的大小(合并左右子树对应窗口的时候根据分割情况可能要进行长或宽上的拉伸)。再根据计算的大小生成窗口的字符串形式,输出。
源代码:
“狗狗搞完40题”中他的代码只有100行,而我居然写了200行……不排除我每个 { 都要新起一行占用了不少行数,不过我很多地方确实写得很水哎……
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define UD -1
#define LR -2
#define maxn 256
#define maxlen 1024
const double EPS = 1e-2;
typedef struct node
{
int w, h; //width height
int type; //split type
int lson, rson;
}node;
node win[maxn];
char str[maxlen][maxlen];
bool isletter(char x)
{
//if (x>='A' && x<='Z') return true;
return false;
if (x!='-' && x!='|') return true;
return false;
}
void streach_w(int k, int w)
{
win[k].w = w;
if (win[k].type>=0) return;
else if (win[k].type==UD)
{
streach_w(win[k].lson, w);
streach_w(win[k].rson, w);
}
else
{
int w1 = (int)(ceil(1.0*w*win[win[k].lson].w/(win[win[k].lson].w+win[win[k].rson].w))+EPS);
streach_w(win[k].lson, w1);
streach_w(win[k].rson, w-w1);
win[k].w=w;
}
}
void streach_h(int k, int h)
{
win[k].h = h;
if (win[k].type>=0) return;
else if (win[k].type==LR)
{
streach_h(win[k].lson, h);
streach_h(win[k].rson, h);
}
else
{
int h1 = (int)(ceil(1.0*h*win[win[k].lson].h/(win[win[k].lson].h+win[win[k].rson].h))+EPS);
streach_h(win[k].lson, h1);
streach_h(win[k].rson, h-h1);
}
}
void print(int w, int h, char str[][maxlen])
{
for (int i=0; i<=h; i++)
{
for (int j=0; j<=w; j++)
printf("%c", str[i][j]);
printf("\n");
}
}
void clear(int h, int w, char str[][maxlen])
{
for (int j=0; j<=w; j++)
str[0][j] = str[h][j] = '-';
for (int i=0; i<=h; i++)
str[i][0] = str[i][w] = '|';
str[0][0] = str[0][w] = str[h][0] = str[h][w] = '*';
for (int i=1; i<h; i++)
for (int j=1; j<w; j++)
str[i][j]=' ';
}
void cre_window(int k, int line1, int line2, int col1, int col2, char str[][maxlen])
{
if (win[k].type>=0)
{
str[line1][col1] = win[k].type + 'A';
return;
}
else if (win[k].type==UD)
{
int line = line1 + win[win[k].lson].h;
for (int i=col1+1; i<col2; i++)
str[line][i] = '-';
str[line][col1] = str[line][col2] = '*';
cre_window(win[k].lson, line1, line, col1, col2, str);
cre_window(win[k].rson, line, line2, col1, col2, str);
}
else //left and right
{
int col = col1 + win[win[k].lson].w;
for (int i=line1+1; i<line2; i++)
str[i][col] = '|';
str[line1][col] = str[line2][col] = '*';
cre_window(win[k].lson, line1, line2, col1, col, str);
cre_window(win[k].rson, line1, line2, col, col2, str);
}
}
int cal_size(int k, int l, int &sum, char tree[])
{
// printf("k=%d l=%d r=%d tree[l]=%c \n", k, l, r, tree[l]);
if (isletter(tree[l]))
{
win[k].w = win[k].h = 2;
win[k].lson = win[k].rson = -1;
win[k].type = tree[l]-'A';
//printf(" k=%2d w=%2d h=%2d type=%c\n", k, win[k].w, win[k].h, win[k].type+'A');
//printf(" lson=%2d rson=%2d\n", win[k].lson, win[k].rson);
if (k==0)
{
clear(win[0].h, win[0].w, str);
cre_window(0, 0, win[0].h, 0, win[0].w, str);
print(win[0].w, win[0].h, str);
}
return l;
}
else{
int tmp;
win[k].lson = ++sum;
tmp = cal_size(win[k].lson, l+1, sum, tree);
win[k].rson = ++sum;
tmp = cal_size(win[k].rson, tmp+1, sum, tree);
win[k].type = (tree[l]=='-') ? UD : LR;
if (win[k].type==UD) //up and down should have the same width
{
if (win[win[k].lson].w!=win[win[k].rson].w)
{
if (win[win[k].lson].w > win[win[k].rson].w)
{
win[k].w = win[win[k].lson].w;
streach_w(win[k].rson, win[k].w);
}
else
{
win[k].w = win[win[k].rson].w;
streach_w(win[k].lson, win[k].w);
}
}
else win[k].w = win[win[k].lson].w;
win[k].h = win[win[k].lson].h + win[win[k].rson].h;
//printf(" k=%2d w=%2d h=%2d type=-\n", k, win[k].w, win[k].h);
//printf(" lson=%2d rson=%2d\n", win[k].lson, win[k].rson);
if (k==0)
{
clear(win[0].h, win[0].w, str);
cre_window(0, 0, win[0].h, 0, win[0].w, str);
print(win[0].w, win[0].h, str);
}
return tmp;
}//(win[k].type==LR)
else //left and right should have the same height
{
if (win[win[k].lson].h!=win[win[k].rson].h)
{
if (win[win[k].lson].h > win[win[k].rson].h)
{
win[k].h = win[win[k].lson].h;
streach_h(win[k].rson, win[k].h);
}
else
{
win[k].h = win[win[k].rson].h;
streach_h(win[k].lson, win[k].h);
}
}
else win[k].h = win[win[k].lson].h;
win[k].w = win[win[k].lson].w + win[win[k].rson].w;
//printf(" k=%2d w=%2d h=%2d type=|\n", k, win[k].w, win[k].h);
//printf(" lson=%2d rson=%2d\n", win[k].lson, win[k].rson);
if (k==0)
{
clear(win[0].h, win[0].w, str);
cre_window(0, 0, win[0].h, 0, win[0].w, str);
print(win[0].w, win[0].h, str);
}
return tmp;
}//(win[k].type=LR)return tmp;
}
return -1;
}
int main(){
int cs, sum;
char tree[maxlen];
node win[maxn];
scanf("%d", &cs);
for (int cases=1; cases<=cs; cases++)
{
sum=0;
scanf("%s", tree);
printf("%d\n", cases);
cal_size(0, 0, sum, tree);
}
return 0;
}