Indiebard

【解题报告】BZOJ2550: [Ctsc2004]公式编辑器

题意:给定一个可视化计算器的操作序列,包括插入数字、字母、运算符、分数、矩阵以及移动光标、矩阵插入行、插入列,输出操作序列结束后的屏显(数学输出)。

 

解法:这题既可以用来提升OI/ACM写大代码模拟题的能力,也可以作为一道不错的C++多态性练习题来写。用二维字符数组buffer进行输出记录,用一个基类Drawable表示屏显元素,以及Character(单个字符)、Sequence(输入框序列)、Fraction(分数)、Matrix(矩阵)派生类。主要虚函数包括:

         virtual void draw(int ix, int iy); //表示以(x,y)为左上点绘制这个Drawable;

         virtual bool insert(Drawable *obj); //表示尝试在当前指针上插入obj;

         virtual void calSize(); //计算当前obj的长宽以及对齐行;

         virtual ~Drawable(){}; //虽然是OI题,但是由于有动态内存声明,最好有重载虚构函数释放内存的部分。

         然后就是大模拟。注意题意即可。

 

代码

  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cmath>
  6 #include <cassert>
  7 #include <algorithm>
  8 #include <string>
  9 #include <vector>
 10 using namespace std;
 11 #define rep(i,n) for(int i=1;i<=(n);++i)
 12 #define rep2(i,a,b) for(int i=(a);i<=(b);++i)
 13 char buffer[1001][1001];
 14 enum Direction
 15 {
 16     UP = 1,
 17     DOWN = 2,
 18     LEFT = 3,
 19     RIGHT = 4
 20 };
 21 class Drawable
 22 {
 23 protected:
 24     int width, height;
 25     int centerX;
 26     Drawable *parent;
 27 public:
 28     Drawable(Drawable *par = 0)
 29     {
 30         parent = par;
 31     }
 32     virtual ~Drawable(){}
 33     virtual void calSize() = 0;
 34     virtual void draw(int ix, int iy) = 0;
 35     virtual bool moveDir(Direction id) = 0;
 36     virtual bool leftMost() = 0;
 37     virtual bool rightMost() = 0;
 38     virtual bool moveHome() = 0;
 39     virtual bool moveEnd() = 0;
 40     virtual bool insert(Drawable *obj) = 0;
 41     virtual bool addRow() = 0;
 42     virtual bool addCol() = 0;
 43     inline int getHeight()
 44     {
 45         return height;
 46     }
 47     inline int getWidth()
 48     {
 49         return width;
 50     }
 51     inline int getUpperHeight()
 52     {
 53         return centerX - 1;
 54     }
 55     inline int getLowerHeight()
 56     {
 57         return height - centerX;
 58     }
 59     inline Drawable *getParent()
 60     {
 61         return parent;
 62     }
 63     inline void setParent(Drawable *par)
 64     {
 65         parent = par;
 66     }
 67 };
 68 class Character :public Drawable
 69 {
 70 private:
 71     char c;
 72 public:
 73     Character(Drawable *par) :Drawable(par)
 74     {
 75         c = 0;
 76     }
 77     Character(char ic, Drawable *par) :Drawable(par)
 78     {
 79         c = ic;
 80     }
 81     virtual ~Character(){}
 82     virtual void calSize()
 83     {
 84         height = 1; centerX = 1;
 85         width = c == 0 ? 0 : c == '-' ? 3 : 1;
 86     }
 87     virtual bool moveDir(Direction id){ return false; }
 88     virtual bool leftMost(){ return false; }
 89     virtual bool rightMost(){ return false; }
 90     virtual bool moveHome(){ return false; }
 91     virtual bool moveEnd(){ return false; }
 92     virtual bool insert(Drawable *obj){ return false; }
 93     virtual bool addRow(){ return false; }
 94     virtual bool addCol(){ return false; }
 95     virtual void draw(int ix, int iy)
 96     {
 97         if (c == 0)return;
 98         if (c == '-')
 99         {
100             buffer[ix][iy] = buffer[ix][iy + 2] = ' ';
101             buffer[ix][iy + 1] = c;
102         }
103         else buffer[ix][iy] = c;
104     }
105 };
106 class Sequence :public Drawable
107 {
108 private:
109     vector<Drawable*> list;
110     int cursor;
111     bool cursorInside;
112     bool insideCursor(Direction);
113     bool outsideCursor(Direction);
114 public:
115     Sequence(Drawable* par) :Drawable(par)
116     {
117         cursor = 0;
118         cursorInside = false;
119     }
120     virtual ~Sequence()
121     {
122         rep2(i, 0, (int)list.size() - 1)
123         {
124             delete list[i];
125         }
126     }
127     virtual void calSize()
128     {
129         width = 0;
130         int upsize = 0, lowsize = 0;
131         rep2(i, 0, (int)list.size() - 1)
132         {
133             list[i]->calSize();
134             width += list[i]->getWidth();
135             upsize = max(upsize, list[i]->getUpperHeight());
136             lowsize = max(lowsize, list[i]->getLowerHeight());
137         }
138         height = upsize + lowsize + 1;
139         centerX = upsize + 1;
140     }
141     virtual bool moveDir(Direction id)
142     {
143         return (insideCursor(id) || outsideCursor(id));
144     }
145     virtual bool leftMost()
146     {
147         cursor = 0;
148         cursorInside = false;
149         return true;
150     }
151     virtual bool rightMost()
152     {
153         cursor = list.size();
154         cursorInside = false;
155         return true;
156     }
157     virtual bool moveHome()
158     {
159         if (cursorInside)return list[cursor]->moveHome();
160         return leftMost();
161     }
162     virtual bool moveEnd()
163     {
164         if (cursorInside)return list[cursor]->moveEnd();
165         return rightMost();
166     }
167     virtual bool insert(Drawable *obj)
168     {
169         if (cursorInside)return list[cursor]->insert(obj);
170         list.insert(list.begin() + cursor, obj);
171         moveDir(RIGHT);
172         obj->setParent(this);
173         return true;
174     }
175     virtual void draw(int ix, int iy)
176     {
177         int tx = ix + centerX - 1;
178         int ty = iy;
179         rep2(i, 0, (int)list.size() - 1)
180         {
181             list[i]->draw(tx - list[i]->getUpperHeight(), ty);
182             ty += list[i]->getWidth();
183         }
184     }
185     virtual bool addRow()
186     {
187         if (cursorInside)return  list[cursor]->addRow();
188         return false;
189     }
190     virtual bool addCol()
191     {
192         if (cursorInside)return  list[cursor]->addCol();
193         return false;
194     }
195 };
196 class Fraction :public Drawable
197 {
198 private:
199     Drawable *u, *d;
200     bool cursorUp;
201 public:
202     Fraction(Drawable *par) :Drawable(par)
203     {
204         u = new Sequence(this);
205         d = new Sequence(this);
206         cursorUp = true;
207     }
208     virtual ~Fraction()
209     {
210         delete u;
211         delete d;
212     }
213     virtual void calSize()
214     {
215         u->calSize();
216         d->calSize();
217         width = max(u->getWidth(), d->getWidth()) + 2;
218         height = u->getHeight() + d->getHeight() + 1;
219         centerX = u->getHeight() + 1;
220     }
221     virtual bool moveDir(Direction id)
222     {
223         if (cursorUp)
224         {
225             if (u->moveDir(id))return true;
226             if (id == DOWN)
227             {
228                 cursorUp = false;
229                 return d->leftMost();
230             }
231         }
232         else
233         {
234             if (d->moveDir(id))return true;
235             if (id == UP)
236             {
237                 cursorUp = true;
238                 return u->leftMost();
239             }
240         }
241         return false;
242     }
243     virtual bool leftMost()
244     {
245         cursorUp = true;
246         return u->leftMost();
247     }
248     virtual bool rightMost()
249     {
250         cursorUp = true;
251         return u->rightMost();
252     }
253     virtual bool moveHome()
254     {
255         return cursorUp ? u->moveHome() : d->moveHome();
256     }
257     virtual bool moveEnd()
258     {
259         return cursorUp ? u->moveEnd() : d->moveEnd();
260     }
261     virtual bool insert(Drawable *obj)
262     {
263         return cursorUp ? u->insert(obj) : d->insert(obj);
264     }
265     virtual void draw(int ix, int iy)
266     {
267         rep(j, width)
268         {
269             buffer[ix + centerX - 1][iy + j - 1] = '-';
270         }
271         u->draw(ix, iy + (width - u->getWidth()) / 2);
272         d->draw(ix + centerX, iy + (width - d->getWidth()) / 2);
273     }
274     virtual bool addRow()
275     {
276         return cursorUp ? u->addRow() : d->addRow();
277     }
278     virtual bool addCol()
279     {
280         return cursorUp ? u->addCol() : d->addCol();
281     }
282 };
283 class Matrix :public Drawable
284 {
285 private:
286     vector< vector<Drawable *> >grid;
287     int nx, ny;
288     vector<int> upSize, downSize, colSize;
289     int cursorX, cursorY;
290 public:
291     Matrix(Drawable *par) :Drawable(par)
292     {
293         vector<Drawable*> tmp;
294         tmp.push_back(new Sequence(this));
295         grid.push_back(tmp);
296         nx = ny = 1;
297     }
298     virtual ~Matrix()
299     {
300         rep2(i, 0, nx-1)
301         {
302             rep2(j, 0, ny-1)
303             {
304                 delete grid[i][j];
305             }
306         }
307     }
308     virtual void calSize()
309     {
310         upSize.clear();
311         downSize.clear();
312         colSize.clear();
313         upSize.resize(nx);
314         downSize.resize(nx);
315         colSize.resize(ny);
316         height = nx - 1; width = ny + 1;
317         rep2(i, 0, nx - 1)
318         {
319             rep2(j, 0, ny - 1)
320             {
321                 grid[i][j]->calSize();
322                 upSize[i] = max(upSize[i], grid[i][j]->getUpperHeight());
323                 downSize[i] = max(downSize[i], grid[i][j]->getLowerHeight());
324                 colSize[j] = max(colSize[j], grid[i][j]->getWidth());
325             }
326         }
327         rep2(i, 0, nx - 1)height += upSize[i] + downSize[i] + 1;
328         rep2(j, 0, ny - 1)width += colSize[j];
329         if (nx % 2)
330         {
331             centerX = nx / 2 + 1 + upSize[nx / 2];
332             rep2(i, 0, nx / 2 - 1)
333             {
334                 centerX += upSize[i] + downSize[i] + 1;
335             }
336         }
337         else
338         {
339             centerX = nx / 2;
340             rep2(i, 0, nx / 2 - 1)
341             {
342                 centerX += upSize[i] + downSize[i] + 1;
343             }
344         }
345     }
346     virtual bool moveDir(Direction id)
347     {
348         if (grid[cursorX][cursorY]->moveDir(id))return true;
349         if (id == UP)
350         {
351             if (cursorX > 0)return grid[--cursorX][cursorY]->leftMost();
352         }
353         else if (id == DOWN)
354         {
355             if (cursorX < nx - 1)return grid[++cursorX][cursorY]->leftMost();
356         }
357         else if (id == LEFT)
358         {
359             if (cursorY > 0)return grid[cursorX][--cursorY]->rightMost();
360         }
361         else if (id == RIGHT)
362         {
363             if (cursorY < ny - 1)return grid[cursorX][++cursorY]->leftMost();
364         }
365         return false;
366     }
367     virtual bool leftMost()
368     {
369         return grid[cursorX = (nx - 1) / 2][cursorY = 0]->leftMost();
370     }
371     virtual bool rightMost()
372     {
373         return grid[cursorX = (nx - 1) / 2][cursorY = ny - 1]->rightMost();
374     }
375     virtual bool moveHome()
376     {
377         return grid[cursorX][cursorY]->moveHome();
378     }
379     virtual bool moveEnd()
380     {
381         return grid[cursorX][cursorY]->moveEnd();
382     }
383     virtual bool insert(Drawable *obj)
384     {
385         return grid[cursorX][cursorY]->insert(obj);
386     }
387     virtual void draw(int ix, int iy)
388     {
389         int tx = ix;
390         rep2(i, 0, nx - 1)
391         {
392             tx += upSize[i];
393             int ty = iy + 1;
394             buffer[tx][ty - 1] = '[';
395             rep2(j, 0, ny - 1)
396             {
397                 grid[i][j]->draw(tx - grid[i][j]->getUpperHeight(), ty + (colSize[j] - grid[i][j]->getWidth()) / 2);
398                 ty += colSize[j] + 1;
399             }
400             buffer[tx][ty - 1] = ']';
401             tx += downSize[i] + 2;
402         }
403     }
404     virtual bool addCol()
405     {
406         if (grid[cursorX][cursorY]->addCol())return true;
407         ++ny;
408         rep2(i, 0, nx - 1)
409         {
410             grid[i].insert(grid[i].begin() + cursorY, new Sequence(this));
411         }
412         return true;
413     }
414     virtual bool addRow()
415     {
416         if (grid[cursorX][cursorY]->addRow())return true;
417         ++nx;
418         vector<Drawable*> tmp;
419         rep2(j, 0, ny - 1)
420         {
421             tmp.push_back(new Sequence(this));
422         }
423         grid.insert(grid.begin() + cursorX, tmp);
424         return true;
425     }
426 };
427 bool Sequence::insideCursor(Direction id)
428 {
429     if (cursorInside)
430     {
431         if (list[cursor]->moveDir(id))return true;
432         if (id == LEFT)
433         {
434             cursorInside = false;
435             return true;
436         }
437         else if (id == RIGHT)
438         {
439             cursorInside = false;
440             ++cursor;
441             return true;
442         }
443     }
444     return false;
445 }
446 bool Sequence::outsideCursor(Direction id)
447 {
448     if (!cursorInside)
449     {
450         if (id == LEFT&&cursor>0)
451         {
452             if (list[cursor - 1]->rightMost())
453             {
454                 --cursor;
455                 cursorInside = true;
456             }
457             else
458             {
459                 --cursor;
460             }
461             return true;
462         }
463         else if (id == RIGHT&&cursor<(int)list.size())
464         {
465             if (list[cursor]->leftMost())
466             {
467                 cursorInside = true;
468             }
469             else
470             {
471                 ++cursor;
472             }
473             return true;
474         }
475     }
476     return false;
477 }
478 class Scanner
479 {
480 private:
481     Sequence root;
482 public:
483     Scanner() :root(0)
484     {
485 
486     }
487     void init()
488     {
489         memset(buffer, ' ', sizeof buffer);
490     }
491     bool scan()
492     {
493         char input[10];
494         if (!(cin >> input))return false;
495         if (strcmp(input, "Fraction") == 0)
496             root.insert(new Fraction(0));
497         else if (strcmp(input, "Matrix") == 0)
498             root.insert(new Matrix(0));
499         else if (strcmp(input, "AddRow") == 0)
500             root.addRow();
501         else if (strcmp(input, "AddCol") == 0)
502             root.addCol();
503         else if (strcmp(input, "Right") == 0)
504             root.moveDir(RIGHT);
505         else if (strcmp(input, "Left") == 0)
506             root.moveDir(LEFT);
507         else if (strcmp(input, "Up") == 0)
508             root.moveDir(UP);
509         else if (strcmp(input, "Down") == 0)
510             root.moveDir(DOWN);
511         else if (strcmp(input, "Home") == 0)
512             root.moveHome();
513         else if (strcmp(input, "End") == 0)
514             root.moveEnd();
515         else
516             root.insert(new Character(input[0], 0));
517 
518         return true;
519     }
520     void print()
521     {
522         root.calSize();
523         root.draw(0, 0);
524         int nx = root.getHeight(), ny = root.getWidth();
525         int ty;
526         rep2(ix, 0, nx - 1)
527         {
528             for (ty = ny; ty >= 0; --ty)if (buffer[ix][ty] != ' ')break;
529             rep2(iy, 0, ty)putchar(buffer[ix][iy]);
530             putchar('\n');
531         }
532     }
533 }scanner;
534 
535 int main()
536 {
537     scanner.init();
538     while (scanner.scan());
539     scanner.print();
540     return 0;
541 }

 

转载请注明出处:http://www.cnblogs.com/instr3/p/4803663.html

posted on 2015-09-12 21:42  Indiebard  阅读(630)  评论(0编辑  收藏  举报

导航