POJ1108_Split Windows 解题报告

Split Windows

题目链接:http://poj.org/problem?id=1108

题目大意:

给你一棵二叉树的先序遍历,有三种字符:|、-、A~Z,然后用窗口表示出来,|: 表示将当前窗口分为左右两半;-: 表示将当前窗口分为上下两半;A~Z: 为当前窗口命名。初始状态为一个大窗口,比如先序序列:|A-BC 表示,当然,形状是不长这样的,具体看样例,但大概意思就是这样。对于每一个小窗口,首先要做到最简,然后和旁边的窗口合并的时候要注意比例,如果出现小数,就左边的、上面的进一,右边的、下面的舍去小数。

题目解法:

并没有用到什么特殊的算法或者数据结构,只要懂得二叉树,接下来模拟即可,这道题做起来感觉挺有意思的。

一.     首先声明一个二叉树的数据结构

1 typedef struct node     //树结点
2 {
3   char c;               //保存该树结点的字符
4   int row,col;          //保存该树结点的行和列,最后就是通过这个来绘制图形
5   struct node *fa;      //父结点
6   struct node *lchild;  //左孩子
7   struct node *rchild;  //右孩子
8 }TreeNode;

二.     根据先序序列来构造这样的一根二叉树

 1 TreeNode *Creat(char *s,int &ls)    //根据 先序遍历 来构建这棵二叉树
 2 {
 3   TreeNode *T=Init();               //申请空间
 4   T->c=s[ls++];                     //赋值
 5   if(s[ls-1]==‘-‘||s[ls-1]==‘|‘)    //如果这个结点不是叶子结点,就继续创建左右孩子
 6   {
 7     T->lchild=Creat(s,ls);
 8     if(T->lchild) T->lchild->fa=T;
 9     T->rchild=Creat(s,ls);
10     if(T->rchild) T->rchild->fa=T;
11   }
12   return T;                         //返回树结点的地址
13 }

三.     封装几个常用的函数

 1 TreeNode *Look_min(TreeNode *T)  //返回T子树的最左叶结点
 2 {
 3   while(T->lchild)
 4   {
 5     T=T->lchild;
 6   }
 7   return T;
 8 }
 9
10 TreeNode *Look_max(TreeNode *T)  //返回T子树的最右叶结点
11 {
12   while(T->rchild)
13   {
14     T=T->rchild;
15   }
16   return T;
17 }
18
19 TreeNode *Look_fa(TreeNode *T)   //查找结点T和T的前驱共同的祖先(第一个),如果T是第一个结点就返回NULL
20 {
21   while(T->fa)
22   {
23     if(T==T->fa->rchild)
24     {
25       return T->fa;
26     }
27     else T=T->fa;
28   }
29   return NULL;
30 }
31
32 TreeNode *Look_pre(TreeNode *T)  //查找结点T的前驱,如果没有前驱就返回NULL,这里说的前驱必须是叶结点
33 {
34   while(T->fa)
35   {
36     if(T==T->fa->rchild)
37     {
38       return Look_max(T->fa->lchild);
39     }
40     else T=T->fa;
41   }
42   return NULL;
43 }

四.     * 通过递归来计算每个大写字符应在的行和列

  1 void Calculate_H(TreeNode *T,int mh,int h,int maxh,int minh)
  2 {
  3   if(T)
  4   {
  5     Calculate_H(T->lchild,mh,h,maxh,minh);
  6     if(T->c!=‘|‘&&T->c!=‘-‘)
  7     {
  8       int height=h-T->row;
  9       height=maxh*height/minh;
 10       T->row=mh-height+1;
 11     }
 12     Calculate_H(T->rchild,mh,h,maxh,minh);
 13   }
 14 }
 15
 16 void Calculate_L(TreeNode *T,int ml,int l,int maxl,int minl)
 17 {
 18   if(T)
 19   {
 20     Calculate_L(T->lchild,ml,l,maxl,minl);
 21     if(T->c!=‘|‘&&T->c!=‘-‘)
 22     {
 23       int length=l-T->col;
 24       length=maxl*length/minl;
 25       T->col=ml-length+1;
 26     }
 27     Calculate_L(T->rchild,ml,l,maxl,minl);
 28   }
 29 }
 30
 31 void Calculate_HL(TreeNode *T)
 32 {
 33   if(T)
 34   {
 35     Calculate_HL(T->lchild);
 36     if(T->c!=‘|‘&&T->c!=‘-‘)        //即叶子结点,就是大写字符
 37     {
 38       TreeNode *pre=Look_pre(T);    //首先计算T结点的前驱
 39       if(pre==NULL)                 //如果前驱为NULL,即第一个大写字母,这个点所在的行就是第一行,列是第一列
 40       {
 41         T->col=1;
 42         T->row=1;
 43       }
 44       else                          //如果不是第一个字母
 45       {
 46         TreeNode *fa=Look_fa(T);    //因为前面排除了第一个字母,所以这里肯定有前驱,也就肯定有和前驱共享的第一个父结点
 47         if(fa->c==‘|‘)              //如果父结点的字符是‘|‘
 48         {
 49           T->row=Look_min(fa)->row; //那么他的行数和最左孩子是一个档次的,即都为这个被左右分成两半的窗口的第一行
 50           T->col=fa->col+2;         //他的列在这个窗口中则是左边最大列数加2(中间有个-)
 51         }
 52         else
 53         {
 54           T->row=fa->row+2;         //同上,这里的每个结点保存的都是以他为根的子树的最大行数或者最大列数
 55           /*
 56               注意递归程序的执行,首先左子树,算完左子树就轮到根结点(中序遍历),然后更新根结点的行数为左子树的行数
 57           就是下面那个else的执行内容,然后算右子树的时候,就可以直接使用根结点的行来表示左子树的最大行数,等右子树计
 58           算完,再有后序遍历来重新更新根结点的值为两边的最大值
 59           */
 60           T->col=Look_min(fa)->col;
 61         }
 62       }
 63     }
 64     else
 65     {
 66       T->col=T->lchild->col;  //更新根结点的行和列,注意这里遇到的只会是‘|‘或‘-‘
 67       T->row=T->lchild->row;
 68     }
 69     Calculate_HL(T->rchild);
 70     if(T->c==‘|‘||T->c==‘-‘)
 71     {
 72       T->row=T->row>T->rchild->row?T->row:T->rchild->row;  //这个就是后序遍历更新根结点的位置
 73       T->col=T->col>T->rchild->col?T->col:T->rchild->col;
 74       /*
 75           最后,如果这个根结点的字符是‘|‘,就是左右分开这个窗口,那么要计算两边的行,按比例更新行的大小,如果是‘-‘,同样
 76       也要更新上下两个子窗口的列
 77       */
 78       if(T->c==‘|‘)
 79       {
 80         int mr_lchild=T->lchild->row;  //左子树的最大行数
 81         int mr_rchild=T->rchild->row;  //右子树的最大行数
 82         if(mr_lchild>mr_rchild)        //右子树比较低,那么要按照比例拉伸右子树
 83         {
 84           int mh=mr_lchild+1;          //先将行转化为高度,下面是细节。
 85           int h=mr_rchild+2;
 86           int maxh=mh-Look_min(T->lchild)->row+1;
 87           int minh=h-Look_min(T->rchild)->row;
 88           Calculate_H(T->rchild,mh,h,maxh,minh);
 89         }
 90         else
 91         {
 92           int mh=mr_rchild+1;
 93           int h=mr_lchild+2;
 94           int maxh=mh-Look_min(T->lchild)->row+1;
 95           int minh=h-Look_min(T->rchild)->row;
 96           Calculate_H(T->lchild,mh,h,maxh,minh);
 97         }
 98       }
 99       else  //同上
100       {
101         int mc_lchild=T->lchild->col;
102         int mc_rchild=T->rchild->col;
103         if(mc_lchild>mc_rchild)
104         {
105           int ml=mc_lchild+1;
106           int l=mc_rchild+2;
107           int maxl=ml-Look_min(T->lchild)->col+1;
108           int minl=l-Look_min(T->rchild)->col;
109           Calculate_L(T->rchild,ml,l,maxl,minl);
110         }
111         else
112         {
113           int ml=mc_rchild+1;
114           int l=mc_lchild+2;
115           int maxl=ml-Look_min(T->lchild)->col+1;
116           int minl=l-Look_min(T->rchild)->col;
117           Calculate_L(T->lchild,ml,l,maxl,minl);
118         }
119       }
120     }
121   }
122 }

五.     通过递归来画出窗口基本的骨架

 1 char tu[100][100];           //保存最终的图
 2
 3 void Draw(TreeNode *T)
 4 {
 5   if(T)
 6   {
 7     Draw(T->lchild);
 8     if(T->c!=‘|‘&&T->c!=‘-‘)    //如果是字母的话,那么在那一行,那一列,填上字母
 9     {
10       tu[T->row][T->col]=T->c;
11     }
12     else if(T->c==‘|‘)          //如果左右分的话,那么在右窗口所属的那个字母的列上画‘|‘,起点h1,终点h2
13     {
14       TreeNode *tmp=Look_min(T->rchild);  //右窗口所属的那一个字母就是右子树的最左孩子
15       int h1=tmp->row+1,h2=h1;            //起点就是这个字母的下一格,先假设终点等于起点
16       TreeNode *fa=T->fa;  //现在要找的是这个结点的祖先并且是‘-‘(并且这个结点是在他的左子树),这样,他右孩子的最左孩子就是目标
17       if(!fa) h2=T->row;   //特殊情况处理,如果为NULL,那么这一竖就是直接竖到底的,就是T的行数
18       bool flag;           //标记结点是他的父结点的左孩子还是右孩子,0 是左孩子,1是右孩子
19       if(fa&&fa->lchild==T) flag=0;  //下面就是找目标的过程
20       else flag=1;
21       while(fa)
22       {
23         if(fa->c==‘-‘&&flag==0)
24         {
25           h2=Look_min(fa->rchild)->row;
26           break;
27         }
28         else
29         {
30           h2=fa->row;
31         }
32         if(fa->fa&&fa->fa->lchild==fa) flag=0;
33         else flag=1;
34         fa=fa->fa;
35       }
36       while(h1<h2)             //确定了起点和终点,就可以开始画线了
37       {
38         tu[h1++][tmp->col]=‘|‘;
39       }
40       /*
41           下面过程不能直接忽略,因为如果*都留到最后处理,会很麻烦。
42       */
43       if(tu[h1][tmp->col]<=‘Z‘&&tu[h1][tmp->col]>=‘A‘);  //竖到头后,那个点一般是*,或者有可能遇到字母,就忽略
44       else
45       {
46         tu[h1][tmp->col]=‘*‘;
47       }
48     }
49     else //同上
50     {
51       TreeNode *tmp=Look_min(T->rchild);
52       int l1=tmp->col+1,l2=l1;
53       TreeNode *fa=T->fa;
54       if(!fa) l2=T->col;
55       bool flag;
56       if(fa&&fa->lchild==T) flag=0;
57       else flag=1;
58       while(fa)
59       {
60         if(fa->c==‘|‘&&flag==0)
61         {
62           l2=Look_min(fa->rchild)->col;
63           break;
64         }
65         else
66         {
67           l2=fa->col;
68         }
69         if(fa->fa&&fa->fa->lchild==fa) flag=0;
70         else flag=1;
71         fa=fa->fa;
72       }
73       while(l1<l2)
74       {
75         tu[tmp->row][l1++]=‘-‘;
76       }
77       if( tu[tmp->row][l1]<=‘Z‘&& tu[tmp->row][l1]>=‘A‘);
78       else
79       {
80          tu[tmp->row][l1]=‘*‘;
81       }
82     }
83     Draw(T->rchild);
84   }
85 }

六.     修补这个图

 1 void Fix(TreeNode *T)        //修补残图
 2 {
 3   //首先是边界线
 4   for(int i=1;i<=T->col;i++)
 5   {
 6     if(tu[1][i]==0)
 7     {
 8       tu[1][i]=‘-‘;
 9       if(tu[2][i]!=0) tu[1][i]=‘*‘;
10     }
11     if(tu[T->row][i]==0)
12     {
13       tu[T->row][i]=‘-‘;
14       if(tu[T->row-1][i]!=0) tu[T->row][i]=‘*‘;
15     }
16   }
17   for(int i=1;i<=T->row;i++)
18   {
19     if(tu[i][1]==0)
20     {
21       tu[i][1]=‘|‘;
22       if(tu[i][2]!=0) tu[i][1]=‘*‘;
23     }
24     if(tu[i][T->col]==0)
25     {
26       tu[i][T->col]=‘|‘;
27       if(tu[i][T->col-1]!=0) tu[i][T->col]=‘*‘;
28     }
29   }
30   //然后是四个顶点
31   if(tu[1][T->col]<=‘Z‘&&tu[1][T->col]>=‘A‘);
32   else tu[1][T->col]=‘*‘;
33   if(tu[1][1]<=‘Z‘&&tu[1][1]>=‘A‘);
34   else tu[1][1]=‘*‘;
35   if(tu[T->row][1]<=‘Z‘&&tu[T->row][1]>=‘A‘);
36   else tu[T->row][1]=‘*‘;
37   if(tu[T->row][T->col]<=‘Z‘&&tu[T->row][T->col]>=‘A‘);
38   else tu[T->row][T->col]=‘*‘;
39   //最后是有交叉的地方,要变成*号
40   for(int i=1;i<=T->row;i++)
41   {
42     for(int j=1;j<=T->col;j++)
43     {
44       if(tu[i][j]!=0&&(tu[i][j]<‘A‘||tu[i][j]>‘Z‘))
45       {
46         int co=0;
47         if(tu[i-1][j]!=0) co++;
48         if(tu[i][j-1]!=0) co++;
49         if(tu[i+1][j]!=0) co++;
50         if(tu[i][j+1]!=0) co++;
51         if(co>=3) tu[i][j]=‘*‘;
52       }
53     }
54   }
55 }

  注意在主函数中,计算完行列以后,要先将根结点的行列都加2(除非他直接是字母),因为边框的原因。

  

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4
  5 typedef struct node     //树结点
  6 {
  7   char c;               //保存该树结点的字符
  8   int row,col;          //保存该树结点的行和列,最后就是通过这个来绘制图形
  9   struct node *fa;      //父结点
 10   struct node *lchild;  //左孩子
 11   struct node *rchild;  //右孩子
 12 }TreeNode;
 13
 14 TreeNode *Init()  //初始化树结点
 15 {
 16   TreeNode *x;
 17   x=(TreeNode *)malloc(sizeof(TreeNode));
 18   x->fa=NULL;
 19   x->row=x->col=0;
 20   x->lchild=NULL;
 21   x->rchild=NULL;
 22   return x;
 23 }
 24
 25 TreeNode *Creat(char *s,int &ls)    //根据 先序遍历 来构建这棵二叉树
 26 {
 27   TreeNode *T=Init();               //申请空间
 28   T->c=s[ls++];                     //赋值
 29   if(s[ls-1]==‘-‘||s[ls-1]==‘|‘)    //如果这个结点不是叶子结点,就继续创建左右孩子
 30   {
 31     T->lchild=Creat(s,ls);
 32     if(T->lchild) T->lchild->fa=T;
 33     T->rchild=Creat(s,ls);
 34     if(T->rchild) T->rchild->fa=T;
 35   }
 36   return T;                         //返回树结点的地址
 37 }
 38
 39 void Dis(TreeNode *T)   //查看生成的二叉树所用。(先序遍历)
 40 {
 41   if(T)
 42   {
 43     if(T->lchild==NULL)
 44     {
 45       printf("自己:%c  行数:%d  列数:%d\n",T->c,T->row,T->col);
 46     }
 47     Dis(T->lchild);
 48     Dis(T->rchild);
 49   }
 50 }
 51
 52 void Clear(TreeNode *T)  //收回动态申请的空间
 53 {
 54   if(T)
 55   {
 56     Clear(T->lchild);
 57     Clear(T->rchild);
 58     free(T);
 59   }
 60 }
 61
 62 TreeNode *Look_min(TreeNode *T)  //返回T子树的最左叶结点
 63 {
 64   while(T->lchild)
 65   {
 66     T=T->lchild;
 67   }
 68   return T;
 69 }
 70
 71 TreeNode *Look_max(TreeNode *T)  //返回T子树的最右叶结点
 72 {
 73   while(T->rchild)
 74   {
 75     T=T->rchild;
 76   }
 77   return T;
 78 }
 79
 80 TreeNode *Look_fa(TreeNode *T)   //查找结点T和T的前驱共同的祖先(第一个),如果T是第一个结点就返回NULL
 81 {
 82   while(T->fa)
 83   {
 84     if(T==T->fa->rchild)
 85     {
 86       return T->fa;
 87     }
 88     else T=T->fa;
 89   }
 90   return NULL;
 91 }
 92
 93 TreeNode *Look_pre(TreeNode *T)  //查找结点T的前驱,如果没有前驱就返回NULL,这里说的前驱必须是叶结点
 94 {
 95   while(T->fa)
 96   {
 97     if(T==T->fa->rchild)
 98     {
 99       return Look_max(T->fa->lchild);
100     }
101     else T=T->fa;
102   }
103   return NULL;
104 }
105
106 void Calculate_H(TreeNode *T,int mh,int h,int maxh,int minh)
107 {
108   if(T)
109   {
110     Calculate_H(T->lchild,mh,h,maxh,minh);
111     if(T->c!=‘|‘&&T->c!=‘-‘)
112     {
113       int height=h-T->row;
114       height=maxh*height/minh;
115       T->row=mh-height+1;
116     }
117     Calculate_H(T->rchild,mh,h,maxh,minh);
118   }
119 }
120
121 void Calculate_L(TreeNode *T,int ml,int l,int maxl,int minl)
122 {
123   if(T)
124   {
125     Calculate_L(T->lchild,ml,l,maxl,minl);
126     if(T->c!=‘|‘&&T->c!=‘-‘)
127     {
128       int length=l-T->col;
129       length=maxl*length/minl;
130       T->col=ml-length+1;
131     }
132     Calculate_L(T->rchild,ml,l,maxl,minl);
133   }
134 }
135
136 void Calculate_HL(TreeNode *T)
137 {
138   if(T)
139   {
140     Calculate_HL(T->lchild);
141     if(T->c!=‘|‘&&T->c!=‘-‘)        //即叶子结点,就是大写字符
142     {
143       TreeNode *pre=Look_pre(T);    //首先计算T结点的前驱
144       if(pre==NULL)                 //如果前驱为NULL,即第一个大写字母,这个点所在的行就是第一行,列是第一列
145       {
146         T->col=1;
147         T->row=1;
148       }
149       else                          //如果不是第一个字母
150       {
151         TreeNode *fa=Look_fa(T);    //因为前面排除了第一个字母,所以这里肯定有前驱,也就肯定有和前驱共享的第一个父结点
152         if(fa->c==‘|‘)              //如果父结点的字符是‘|‘
153         {
154           T->row=Look_min(fa)->row; //那么他的行数和最左孩子是一个档次的,即都为这个被左右分成两半的窗口的第一行
155           T->col=fa->col+2;         //他的列在这个窗口中则是左边最大列数加2(中间有个-)
156         }
157         else
158         {
159           T->row=fa->row+2;         //同上,这里的每个结点保存的都是以他为根的子树的最大行数或者最大列数
160           /*
161               注意递归程序的执行,首先左子树,算完左子树就轮到根结点(中序遍历),然后更新根结点的行数为左子树的行数
162           就是下面那个else的执行内容,然后算右子树的时候,就可以直接使用根结点的行来表示左子树的最大行数,等右子树计
163           算完,再有后序遍历来重新更新根结点的值为两边的最大值
164           */
165           T->col=Look_min(fa)->col;
166         }
167       }
168     }
169     else
170     {
171       T->col=T->lchild->col;  //更新根结点的行和列,注意这里遇到的只会是‘|‘或‘-‘
172       T->row=T->lchild->row;
173     }
174     Calculate_HL(T->rchild);
175     if(T->c==‘|‘||T->c==‘-‘)
176     {
177       T->row=T->row>T->rchild->row?T->row:T->rchild->row;  //这个就是后序遍历更新根结点的位置
178       T->col=T->col>T->rchild->col?T->col:T->rchild->col;
179       /*
180           最后,如果这个根结点的字符是‘|‘,就是左右分开这个窗口,那么要计算两边的行,按比例更新行的大小,如果是‘-‘,同样
181       也要更新上下两个子窗口的列
182       */
183       if(T->c==‘|‘)
184       {
185         int mr_lchild=T->lchild->row;  //左子树的最大行数
186         int mr_rchild=T->rchild->row;  //右子树的最大行数
187         if(mr_lchild>mr_rchild)        //右子树比较低,那么要按照比例拉伸右子树
188         {
189           int mh=mr_lchild+1;          //先将行转化为高度,下面是细节。
190           int h=mr_rchild+2;
191           int maxh=mh-Look_min(T->lchild)->row+1;
192           int minh=h-Look_min(T->rchild)->row;
193           Calculate_H(T->rchild,mh,h,maxh,minh);
194         }
195         else
196         {
197           int mh=mr_rchild+1;
198           int h=mr_lchild+2;
199           int maxh=mh-Look_min(T->lchild)->row+1;
200           int minh=h-Look_min(T->rchild)->row;
201           Calculate_H(T->lchild,mh,h,maxh,minh);
202         }
203       }
204       else  //同上
205       {
206         int mc_lchild=T->lchild->col;
207         int mc_rchild=T->rchild->col;
208         if(mc_lchild>mc_rchild)
209         {
210           int ml=mc_lchild+1;
211           int l=mc_rchild+2;
212           int maxl=ml-Look_min(T->lchild)->col+1;
213           int minl=l-Look_min(T->rchild)->col;
214           Calculate_L(T->rchild,ml,l,maxl,minl);
215         }
216         else
217         {
218           int ml=mc_rchild+1;
219           int l=mc_lchild+2;
220           int maxl=ml-Look_min(T->lchild)->col+1;
221           int minl=l-Look_min(T->rchild)->col;
222           Calculate_L(T->lchild,ml,l,maxl,minl);
223         }
224       }
225     }
226   }
227 }
228
229 char tu[100][100];           //保存最终的图
230
231 void Draw(TreeNode *T)
232 {
233   if(T)
234   {
235     Draw(T->lchild);
236     if(T->c!=‘|‘&&T->c!=‘-‘)    //如果是字母的话,那么在那一行,那一列,填上字母
237     {
238       tu[T->row][T->col]=T->c;
239     }
240     else if(T->c==‘|‘)          //如果左右分的话,那么在右窗口所属的那个字母的列上画‘|‘,起点h1,终点h2
241     {
242       TreeNode *tmp=Look_min(T->rchild);  //右窗口所属的那一个字母就是右子树的最左孩子
243       int h1=tmp->row+1,h2=h1;            //起点就是这个字母的下一格,先假设终点等于起点
244       TreeNode *fa=T->fa;  //现在要找的是这个结点的祖先并且是‘-‘(并且这个结点是在他的左子树),这样,他右孩子的最左孩子就是目标
245       if(!fa) h2=T->row;   //特殊情况处理,如果为NULL,那么这一竖就是直接竖到底的,就是T的行数
246       bool flag;           //标记结点是他的父结点的左孩子还是右孩子,0 是左孩子,1是右孩子
247       if(fa&&fa->lchild==T) flag=0;  //下面就是找目标的过程
248       else flag=1;
249       while(fa)
250       {
251         if(fa->c==‘-‘&&flag==0)
252         {
253           h2=Look_min(fa->rchild)->row;
254           break;
255         }
256         else
257         {
258           h2=fa->row;
259         }
260         if(fa->fa&&fa->fa->lchild==fa) flag=0;
261         else flag=1;
262         fa=fa->fa;
263       }
264       while(h1<h2)             //确定了起点和终点,就可以开始画线了
265       {
266         tu[h1++][tmp->col]=‘|‘;
267       }
268       /*
269           下面过程不能直接忽略,因为如果*都留到最后处理,会很麻烦。
270       */
271       if(tu[h1][tmp->col]<=‘Z‘&&tu[h1][tmp->col]>=‘A‘);  //竖到头后,那个点一般是*,或者有可能遇到字母,就忽略
272       else
273       {
274         tu[h1][tmp->col]=‘*‘;
275       }
276     }
277     else //同上
278     {
279       TreeNode *tmp=Look_min(T->rchild);
280       int l1=tmp->col+1,l2=l1;
281       TreeNode *fa=T->fa;
282       if(!fa) l2=T->col;
283       bool flag;
284       if(fa&&fa->lchild==T) flag=0;
285       else flag=1;
286       while(fa)
287       {
288         if(fa->c==‘|‘&&flag==0)
289         {
290           l2=Look_min(fa->rchild)->col;
291           break;
292         }
293         else
294         {
295           l2=fa->col;
296         }
297         if(fa->fa&&fa->fa->lchild==fa) flag=0;
298         else flag=1;
299         fa=fa->fa;
300       }
301       while(l1<l2)
302       {
303         tu[tmp->row][l1++]=‘-‘;
304       }
305       if( tu[tmp->row][l1]<=‘Z‘&& tu[tmp->row][l1]>=‘A‘);
306       else
307       {
308          tu[tmp->row][l1]=‘*‘;
309       }
310     }
311     Draw(T->rchild);
312   }
313 }
314
315 void Fix(TreeNode *T)        //修补残图
316 {
317   //首先是边界线
318   for(int i=1;i<=T->col;i++)
319   {
320     if(tu[1][i]==0)
321     {
322       tu[1][i]=‘-‘;
323       if(tu[2][i]!=0) tu[1][i]=‘*‘;
324     }
325     if(tu[T->row][i]==0)
326     {
327       tu[T->row][i]=‘-‘;
328       if(tu[T->row-1][i]!=0) tu[T->row][i]=‘*‘;
329     }
330   }
331   for(int i=1;i<=T->row;i++)
332   {
333     if(tu[i][1]==0)
334     {
335       tu[i][1]=‘|‘;
336       if(tu[i][2]!=0) tu[i][1]=‘*‘;
337     }
338     if(tu[i][T->col]==0)
339     {
340       tu[i][T->col]=‘|‘;
341       if(tu[i][T->col-1]!=0) tu[i][T->col]=‘*‘;
342     }
343   }
344   //然后是四个顶点
345   if(tu[1][T->col]<=‘Z‘&&tu[1][T->col]>=‘A‘);
346   else tu[1][T->col]=‘*‘;
347   if(tu[1][1]<=‘Z‘&&tu[1][1]>=‘A‘);
348   else tu[1][1]=‘*‘;
349   if(tu[T->row][1]<=‘Z‘&&tu[T->row][1]>=‘A‘);
350   else tu[T->row][1]=‘*‘;
351   if(tu[T->row][T->col]<=‘Z‘&&tu[T->row][T->col]>=‘A‘);
352   else tu[T->row][T->col]=‘*‘;
353   //最后是有交叉的地方,要变成*号
354   for(int i=1;i<=T->row;i++)
355   {
356     for(int j=1;j<=T->col;j++)
357     {
358       if(tu[i][j]!=0&&(tu[i][j]<‘A‘||tu[i][j]>‘Z‘))
359       {
360         int co=0;
361         if(tu[i-1][j]!=0) co++;
362         if(tu[i][j-1]!=0) co++;
363         if(tu[i+1][j]!=0) co++;
364         if(tu[i][j+1]!=0) co++;
365         if(co>=3) tu[i][j]=‘*‘;
366       }
367     }
368   }
369 }
370
371 int main()
372 {
373   //freopen("1.in","r",stdin);
374   //freopen("1.out","w+",stdout);
375   TreeNode *T;
376   char s[100];
377   int t,g=1;
378   scanf("%d",&t);
379   while(t--)
380   {
381     printf("%d\n",g++);
382     scanf("%s",s);
383     int ls=0;
384     T=Creat(s,ls);
385     Calculate_HL(T);
386     memset(tu,0,sizeof(tu));
387     if(T->lchild!=NULL)
388     {
389       T->row+=2;
390       T->col+=2;
391       Draw(T);
392       Fix(T);
393       for(int i=1;i<=T->row;i++)
394       {
395         for(int j=1;j<=T->col;j++)
396         {
397           printf("%c",tu[i][j]==0?‘ ‘:tu[i][j]);
398         }
399         printf("\n");
400       }
401     }
402     else
403     {
404       printf("%c-*\n",T->c);
405       printf("| |\n");
406       printf("*-*\n");
407     }
408     Clear(T);
409   }
410   return 0;
411 }

AC代码

时间: 2024-10-25 17:35:41

POJ1108_Split Windows 解题报告的相关文章

08年acm区域赛北京赛区 部分题解题报告

08年区域赛北京赛区 http://poj.org/searchproblem?field=source&key=Beijing+2008 POJ 3921 Destroying the bus stations 题目还是比较难的,当时的榜似乎只有4/25的通过/提交,其实题目数据很水.学长转换模型写了网络流求最小割,可以AC,不过自己造了个数据推翻了正确性.我写了个很挫的bfs套bfs,外层是最小的删除点数,内层是求最短路,数据很水可以AC.但比较蛋疼的在于bfs耗内存,而且队列中的点数是阶乘

20161027模拟赛解题报告

20161027模拟赛解题报告 By shenben T1 数学题 模拟即可. 注意开long long T2 技巧题 图片为本题第一张图.(无奈,图传不上来) 首先第一问图中的“Y 字形”的数量,这么简单,在此不细讲. 详见代码 O(n)累加一下就好了 主要说说第二问怎么搞 预处理 每个点分别与其他那些点相连 权值为第1,2,3大(若没有2,3大,就忽略).记录一下权值与对应的点的标号.目的是方便下面的判断. 枚举入度>=3的点,即点B(有多个) 再枚举点B相连的D点(不是点A,C). Ste

解题报告 之 HDU5301 Buildings

解题报告 之 HDU5301 Buildings Description Your current task is to make a ground plan for a residential building located in HZXJHS. So you must determine a way to split the floor building with walls to make apartments in the shape of a rectangle. Each buil

解题报告 之 POJ3057 Evacuation

解题报告 之 POJ3057 Evacuation Description Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time

hdu 1541 Stars 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1541 题目意思:有 N 颗星星,每颗星星都有各自的等级.给出每颗星星的坐标(x, y),它的等级由所有比它低层(或者同层)的或者在它左手边的星星数决定.计算出每个等级(0 ~ n-1)的星星各有多少颗. 我只能说,题目换了一下就不会变通了,泪~~~~ 星星的分布是不是很像树状数组呢~~~没错,就是树状数组题来滴! 按照题目输入,当前星星与后面的星星没有关系.所以只要把 x 之前的横坐标加起来就可以了

DAY01 WINDOWS 实验报告

DAY 01   Windows 实验一 实验名称:虚拟机的安装以及win7系统的安装 实验描述:学习安装虚拟机,以及安装不同的系统,可以满足用户不同时期的不同的需求 实验步骤: 步骤1:点击开始-选择vmware文件夹-点击Vmware Workstation                             步骤2:点击文件-新建虚拟机-下一步-选择客户机操作系统和版本-选择虚拟机安装位置-设置虚拟机的处理器.内存等信息-完成虚拟机裸机的安装 步骤3:点击编辑虚拟器-双击CD/DVD(

DAY02 WINDOWS 实验报告

实验一 实验名称: ghost做系统的备份与还原 实验描述:对系统进行备份,可以使用户在电脑中病毒或出故障后,可以还原到一个比较纯净的系统环境 实验步骤: 步骤1:点击编辑虚拟机设置-CD/DVD-选择镜像文件-选择超级急救箱 步骤2:启动虚拟机-进入资源管理器-运行超级急救箱安装文件 步骤3:重启系统-选择超级急救箱-选择ghost32 for winpe 步骤4:进入PE系统以后,点击ghost32程序-选择local->partition->To image-下一步-选择要备份的分区-选

【百度之星2014~初赛(第二轮)解题报告】Chess

声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站,因此,笔者添加此条声明. 郑重声明:这篇记录<[百度之星2014~初赛(第二轮)解题报告]Chess>转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?id=667 前言 最近要毕业了,有半年没做

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh童鞋的提醒. 勘误2:第7题在推断连通的时候条件写错了,后两个if条件中是应该是<=12 落了一个等于号.正确答案应为116. 1.煤球数目 有一堆煤球.堆成三角棱锥形.详细: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形). -. 假设一共