1. 程式人生 > >CCF CSP 2015年12月第3題 畫圖 (模擬+DFS或BFS)

CCF CSP 2015年12月第3題 畫圖 (模擬+DFS或BFS)

問題描述
試題編號: 201512-3
試題名稱: 畫圖
時間限制: 1.0s
記憶體限制: 256.0MB
問題描述: 問題描述   用 ASCII 字元來畫圖是一件有趣的事情,並形成了一門被稱為 ASCII Art 的藝術。例如,下圖是用 ASCII 字元畫出來的 CSPRO 字樣。
  ..____.____..____..____...___..
  ./.___/.___||.._.\|.._.\./._.\.
  |.|...\___.\|.|_).|.|_).|.|.|.|
  |.|___.___).|..__/|.._.<|.|_|.|
  .\____|____/|_|...|_|.\_\\___/.

  本題要求程式設計實現一個用 ASCII 字元來畫圖的程式,支援以下兩種操作:
  Ÿ 畫線:給出兩個端點的座標,畫一條連線這兩個端點的線段。簡便起見題目保證要畫的每條線段都是水平或者豎直的。水平線段用字元 - 來畫,豎直線段用字元 | 來畫。如果一條水平線段和一條豎直線段在某個位置相交,則相交位置用字元 + 代替。
  Ÿ 填充:給出填充的起始位置座標和需要填充的字元,從起始位置開始,用該字元填充相鄰位置,直到遇到畫布邊緣或已經畫好的線段。注意這裡的相鄰位置只需要考慮上下左右 4 個方向,如下圖所示,字元 @ 只和 4 個字元 * 相鄰。
  .*.
  *@*
  .*. 輸入格式   第1行有三個整數m
nqmn分別表示畫布的寬度和高度,以字元為單位。q表示畫圖操作的個數。
  第2行至第q + 1行,每行是以下兩種形式之一:
  Ÿ 0 x1 y1 x2 y2:表示畫線段的操作,(x1y1)和(x2y2)分別是線段的兩端,滿足要麼x1 = x2 且y1 ≠ y2,要麼 y1 = y2 且 x1 ≠ x2
  Ÿ 1 x y c:表示填充操作,(xy)是起始位置,保證不會落在任何已有的線段上;c 為填充字元,是大小寫字母。
  畫布的左下角是座標為 (0, 0) 的位置,向右為x座標增大的方向,向上為y座標增大的方向。這q個操作按照資料給出的順序依次執行。畫布最初時所有位置都是字元 .(小數點)。 輸出格式   輸出有n
行,每行m個字元,表示依次執行這q個操作後得到的畫圖結果。 樣例輸入 4 2 3
1 0 0 B
0 1 0 2 0
1 0 0 A 樣例輸出 AAAA
A--A 樣例輸入 16 13 9
0 3 1 12 1
0 12 1 12 3
0 12 3 6 3
0 6 3 6 9
0 6 9 12 9
0 12 9 12 11
0 12 11 3 11
0 3 11 3 1
1 4 2 C 樣例輸出 ................
...+--------+...
...|CCCCCCCC|...
...|CC+-----+...
...|CC|.........
...|CC|.........
...|CC|.........
...|CC|.........
...|CC|.........
...|CC+-----+...
...|CCCCCCCC|...
...+--------+...
................ 評測用例規模與約定   所有的評測用例滿足:2 ≤ mn ≤ 100,0 ≤ q ≤ 100,0 ≤ x < mx表示輸入資料中所有位置的x座標),0 ≤ y < ny表示輸入資料中所有位置的y座標)。

解題思路:因為只有水平線和垂直線,所以判斷線段相交的時候只需要判斷這個位置有沒有橫線或豎線就行了。如果某個點本來是橫線,而現在要畫一條豎線,那麼該點就要變成'+';要注意如果這個點本身就是'+',那麼劃線之後它仍然是一個'+'。這裡有點小坑,如果不注意的話就只有90分。填充操作也很簡單,DFS和BFS都可以,注意一下邊界就行。還有一個地方是座標的變換,因為題目給的座標是以左下角為原點的,而陣列在計算機中則並不是這樣存的(應該是左上角為(0, 0)),需要進行一個變換。

程式碼如下:

#include <iostream>

using namespace std;
const int maxn = 105;
const int maxm = 105;
char maze[maxm][maxn];
int m, n, q;

void init() {
    for(int i = 0; i <= n; i++) {
        for(int j = 0; j <= m; j++) {
            maze[i][j] = '.';
        }
    }
}
//將座標轉換為陣列下標
void transform(int &x, int &y) {
    int a = x, b= y;
    x = n - b - 1;
    y = a;
    return ;
}

void printLine(int x1, int y1, int x2, int y2) {
    //按照陣列下標操作
    if(x1 == x2) {
        if(y1 > y2) swap(y1, y2);
        for(int j = y1; j <= y2; j++) {
            if(maze[x1][j] == '|' || maze[x1][j] == '+') maze[x1][j] = '+';
            else maze[x1][j] = '-';
        }
    }
    if(y1 == y2) {
        if(x2 > x1) swap(x1, x2);
        for(int i = x2; i <= x1; i++) {
            if(maze[i][y1] == '-' || maze[i][y1] == '+') maze[i][y1] = '+';
            else maze[i][y1] = '|';
        }
    }
    return ;
}

void fillArea(int x, int y, char ch) {
    if(x < 0 || x >= n || y < 0 || y >= m || maze[x][y] == ch ||
            maze[x][y] == '+' || maze[x][y] == '|' || maze[x][y] == '-')
        return ;
    maze[x][y] = ch;
    fillArea(x + 1, y, ch);
    fillArea(x, y + 1, ch);
    fillArea(x - 1, y, ch);
    fillArea(x, y - 1, ch);
    return ;
}

void print() {
    for(int i = 0; i < n; i++) {
        for(int j = 0; j < m; j++) {
            cout << maze[i][j];
        }
        cout << endl;
    }
}

int main(void) {
    cin >> m >> n >> q;
    int x1, x2, y1, y2, op;
    char ch;
    init();
    while(q--) {
        cin >> op;
        if(op == 0) {
            cin >> x1 >> y1 >> x2 >> y2;
            transform(x1, y1);
            transform(x2, y2);
            printLine(x1, y1, x2, y2);
        } else {
            cin >> x1 >> y1 >>ch;
            transform(x1, y1);
            fillArea(x1, y1, ch);
        }
    }
    print();
    return 0;
}