CCF CSP 201512-3.画图

问题描述

  用 ASCII 字符来画图是一件有趣的事情,并形成了一门被称为 ASCII Art 的艺术。例如,下图是用 ASCII 字符画出来的 CSPRO 字样。

1
2
3
4
5
..____.____..____..____...___..
./.___/.___||.._.\|.._.\./._.\.
|.|...\___.\|.|_).|.|_).|.|.|.|
|.|___.___).|..__/|.._.<|.|_|.|
.\____|____/|_|...|_|.\_\\___/.

​ 本题要求编程实现一个用 ASCII 字符来画图的程序,支持以下两种操作:
  Ÿ 画线:给出两个端点的坐标,画一条连接这两个端点的线段。简便起见题目保证要画的每条线段都是水平或者竖直的。水平线段用字符 - 来画,竖直线段用字符 | 来画。如果一条水平线段和一条竖直线段在某个位置相交,则相交位置用字符 + 代替。
  Ÿ 填充:给出填充的起始位置坐标和需要填充的字符,从起始位置开始,用该字符填充相邻位置,直到遇到画布边缘或已经画好的线段。注意这里的相邻位置只需要考虑上下左右 4 个方向,如下图所示,字符 @ 只和 4 个字符 * 相邻。

1
2
3
.*.
*@*
.*.

输入格式

  第1行有三个整数m, nqmn分别表示画布的宽度和高度,以字符为单位。q表示画图操作的个数。
  第2行至第q + 1行,每行是以下两种形式之一:
  Ÿ 0 x1 y1 x2 y2:表示画线段的操作,(x1, y1)和(x2, y2)分别是线段的两端,满足要么x1 = x2 且y1 ≠ y2,要么 y1 = y2 且 x1 ≠ x2。
  Ÿ 1 x y c:表示填充操作,(x, y)是起始位置,保证不会落在任何已有的线段上;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

样例输出

1
2
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

样例输出

1
2
3
4
5
6
7
8
9
10
11
12
13
................
...+--------+...
...|CCCCCCCC|...
...|CC+-----+...
...|CC|.........
...|CC|.........
...|CC|.........
...|CC|.........
...|CC|.........
...|CC+-----+...
...|CCCCCCCC|...
...+--------+...
................

评测用例规模与约定

  所有的评测用例满足:2 ≤ m, n ≤ 100,0 ≤ q ≤ 100,0 ≤ x < mx表示输入数据中所有位置的x坐标),0 ≤ y< ny表示输入数据中所有位置的y坐标)。


分析:

定义一个nxm的二维char型数组graph,存储宽度为m、高度为n的画布。

题目告诉我们,“画布的左下角是坐标为 (0, 0) 的位置,向右为x坐标增大的方向,向上为y坐标增大的方向”。

然而,graph的第0行第0列在左上角,因此需要对给定的画布坐标进行转换。graph的第i行第j列与画布中的点(x,y)的转换关系如下:

1
2
i = n - 1 - y;
j = x;

1.若当前操作为画线段 ——0 x1 y1 x2 y2:

(1)当x1 = x2时,表示画一条从(x1,y1)到(x2,y2)的垂直线,用字符|来画。当遇到字符-或者+时,对应位置的字符变为+;否则,变为字符|。

(2)当y1 = y2时,表示画一条从(x1,y1)到(x2,y2)的水平线,用字符-来画。当遇到字符|或者+时,对应位置的字符变为+;否则,变为字符-。

2.若当前操作为填充——1 x y c

从起始位置(x,y)开始,用字符c填充上下左右 4 个方向的相邻位置,直到遇到画布边缘,或者已经画好的线段,或者该位置已经用字符c填充过了。

填充操作可以采用递归,或者队列来实现。

注意到样例2中0 12 3 6 3,y1 = y2 = 3,而x1 > x2。因此,在画线时,需要比较两个坐标的大小,而不能认为x1 < x2或者y1 < y2一定成立。

  • C++版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <cstdio>
#include <algorithm>
using namespace std;

const int MAX = 100;
char picture[MAX][MAX];
int m, n, q;

// 从起始位置(x,y)开始,用字符c填充相邻位置
void dfs(int x, int y, int c) {
int i = n - 1 - y, j = x;
//如果遇到画布边缘,或者已经画好的线段,或者该位置已经填充过了
if (x < 0 || x >= m || y < 0 || y >= n
|| picture[i][j] == '-' || picture[i][j] == '|' || picture[i][j] == '+'
|| picture[i][j] == c) {
return;
}
picture[i][j] = c;
// 填充相邻位置,上下左右
dfs(x, y + 1, c);
dfs(x, y - 1, c);
dfs(x - 1, y, c);
dfs(x + 1, y, c);
}

int main() {
scanf("%d %d %d", &m, &n, &q);

fill(picture[0], picture[0] + MAX * MAX, '.');

int status, x, y;
while (q--) {
scanf("%d", &status);
// 填充
if (status == 1) {
char c;
scanf("%d %d %c", &x, &y, &c);
dfs(x, y, c);
continue;
}

// 画线段
int x2, y2, i, j;
scanf("%d %d %d %d", &x, &y, &x2, &y2);
// 竖直线段
if (x == x2) {
if (y > y2) {
swap(y, y2);
}
for (; y <= y2; y++) {
i = n - 1 - y;
j = x;
if (picture[i][j] == '-' || picture[i][j] == '+') {
picture[i][j] = '+';
} else {
picture[i][j] = '|';
}
}
} else {
// 水平线段
if (x > x2) {
swap(x, x2);
}
for (; x <= x2; x++) {
i = n - 1 - y;
j = x;
if (picture[i][j] == '|' || picture[i][j] == '+') {
picture[i][j] = '+';
} else {
picture[i][j] = '-';
}
}
}
}

for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
printf("%c", picture[i][j]);
}
printf("\n");
}
return 0;
}
  • Java版

使用递归实现填充操作时,系统报运行错误,得分为90分,可能是出现了栈溢出

故下面的代码,采用队列实现填充操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int m = scan.nextInt();
int n = scan.nextInt();
int q = scan.nextInt();
char[][] graph = new char[n][m];

for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
graph[i][j] = '.';
}
}

for (int k = 0; k < q; k++) {
int status = scan.nextInt();
// 填充
if (status == 1) {
int x = scan.nextInt();
int y = scan.nextInt();
char c = scan.next().charAt(0);
//dfs(graph, x, y, c, m, n);
Queue<Point> qu = new LinkedList<>();
qu.add(new Point(x,y));
while(!qu.isEmpty()) {
Point p = qu.poll();
x = p.x;
y = p.y;
int i = n - 1 - y, j = x;
// 如果遇到画布边缘,或者已经画好的线段,或者该位置已经填充过了
if (x < 0 || x >= m || y < 0 || y >= n
|| graph[i][j] == '-' || graph[i][j] == '|' || graph[i][j] == '+'
|| graph[i][j] == c) {
continue;
}
graph[i][j] = c;
qu.add(new Point(p.x,y+1));
qu.add(new Point(x,y-1));
qu.add(new Point(x-1,y));
qu.add(new Point(x+1,y));
}
continue;
}
// 画线段
int x1 = scan.nextInt();
int y1 = scan.nextInt();
int x2 = scan.nextInt();
int y2 = scan.nextInt();
int i, j, temp;
// 竖直线段
if (x1 == x2) {
if (y1 > y2) {
temp = y1;
y1 = y2;
y2 = temp;
}
for (; y1 <= y2; y1++) {
i = n - 1 - y1;
j = x1;
if (graph[i][j] == '-' || graph[i][j] == '+') {
graph[i][j] = '+';
} else {
graph[i][j] = '|';
}
}
} else {
// 水平线段
if (x1 > x2) {
temp = x1;
x1 = x2;
x2 = temp;
}
for (; x1 <= x2; x1++) {
i = n - 1 - y1;
j = x1;
if (graph[i][j] == '|' || graph[i][j] == '+') {
graph[i][j] = '+';
} else {
graph[i][j] = '-';
}
}
}
}

scan.close();

StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
sb.append(graph[i][j]);
}
sb.append('\n');
}
System.out.println(sb.toString());
}

// 使用递归,得分90,显示运行错误,可能是递归层数过深,导致栈溢出
/*public static void dfs(char[][] graph, int x, int y, char c, int m, int n) {
int i = n - 1 - y, j = x;
// 如果遇到画布边缘,或者已经画好的线段,或者该位置已经填充过了
if (x < 0 || x >= m || y < 0 || y >= n || graph[i][j] == '-' || graph[i][j] == '|' || graph[i][j] == '+'
|| graph[i][j] == c) {
return;
}
graph[i][j] = c;
// 填充相邻位置,上下左右
dfs(graph, x, y + 1, c, m, n);
dfs(graph, x, y - 1, c, m, n);
dfs(graph, x - 1, y, c, m, n);
dfs(graph, x + 1, y, c, m, n);

}*/
}
class Point {
int x,y;

public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
}

----------本文结束感谢您的阅读----------
坚持原创技术分享,您的支持将鼓励我继续创作!