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