【解题报告】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