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;
}