题意
本题要求实现一个用ASCII字符来画图的程序,支持以下两种操作:
- 画线
给出两个端点的坐标,画一条连接这两个端点的线段。简便起见题目保证要画的每条线段都是水平或者竖直的。水平线段用字符 - 来画,竖直线段用字符 | 来画。如果一条水平线段和一条竖直线段在某个位置相交,则相交位置用字符 + 代替。
- 填充
给出填充的起始位置坐标和需要填充的字符,从起始位置开始,用该字符填充相邻位置,直到遇到画布边缘或已经画好的线段,注意这里的相邻位置只需要考虑上下左右 4 个方向。
Input
第1行有三个整数m, n和q。m和n分别表示画布的宽度和高度,以字符为单位。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个操作按照数据给出的顺序依次执行。画布最初时所有位置都是字符
.
.
.(小数点)。
Output
输出有n行,每行m个字符,表示依次执行这q个操作后得到的画图结果。
Sample Input
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
Sample Output
思路
(1)坐标转换:
由于题目所给坐标与所创建的二维数组的坐标不同,故首先要进行坐标转换,设输入坐标
(
x
x
,
y
y
)
(xx,yy)
(xx,yy),对应二维数组的下标为
(
x
,
y
)
(x,y)
(x,y),则有以下对应关系:
y
=
x
x
,
x
=
n
−
1
−
y
y
y=xx,x=n-1-yy
y=xx,x=n−1−yy
(2)画线
这里使用的是转换后的数组下标
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
(x1,y1),(x2,y2)
(x1,y1),(x2,y2),若
x
1
=
x
2
x1=x2
x1=x2 则说明接下来要换的是水平线,选取画图起点
f
r
o
m
=
m
i
n
(
y
1
,
y
2
)
,
t
o
=
m
a
x
(
y
1
,
y
2
)
from=min(y1,y2),to=max(y1,y2)
from=min(y1,y2),to=max(y1,y2),然后遍历数组下标为
(
x
1
,
f
r
o
m
−
>
t
o
)
(x1,from->to)
(x1,from−>to)的点,若值为
∣
|
∣ 或
+
+
+,则覆盖为
+
+
+,其余点覆盖为
−
-
−,画竖直线时情况与画水平线类似。
(3)填充
以转换后的坐标
(
x
,
y
)
(x,y)
(x,y)为起点执行BFS来对相邻区域进行填充,注意填充条件:
(i)填充点的值不等于当前填充字符以及任何线段(包括 + )
(ii)填充点在边界内
代码实现
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
int m,n,q,x1,y1,x2,y2,op;
int dis[][2]={{1,0},{-1,0},{0,1},{0,-1}};
char a[110][110];
char c;
struct s{
int x;
int y;
s(){}
s(int xx,int yy):x(xx),y(yy){}
};
void transform(int &x,int &y){
int xx=x;
int yy=y;
y=xx;
x=n-1-yy;
}
void DrawLine(int x1,int y1,int x2,int y2){
transform(x1,y1);
transform(x2,y2);
//画横线
if(x1==x2){
int from=min(y1,y2);
int to=max(y1,y2);
for(int j=from;j<=to;j++){
if(a[x1][j]=='|'||a[x1][j]=='+'){
a[x1][j]='+';
}
else{
a[x1][j]='-';
}
}
}
//画竖线
else{
int from=min(x1,x2);
int to=max(x1,x2);
for(int i=from;i<=to;i++){
if(a[i][y1]=='-'||a[i][y1]=='+'){
a[i][y1]='+';
}
else{
a[i][y1]='|';
}
}
}
}
void DrawChar(int x,int y,char c){
transform(x,y);
queue<s> q;
q.push(s(x,y));
if(a[x][y]!='|'&&a[x][y]!='+'&&a[x][y]!='-')
a[x][y]=c;
while(!q.empty()){
s t=q.front();
q.pop();
for(int i=0;i<4;i++){
int dx=t.x+dis[i][0];
int dy=t.y+dis[i][1];
if(a[dx][dy]!=c&&a[dx][dy]!='|'&&a[dx][dy]!='+'&&a[dx][dy]!='-'&&dx>=0&&dx<n&&dy>=0&&dy<m){
a[dx][dy]=c;
q.push(s(dx,dy));
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>m>>n>>q;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
a[i][j]='.';
}
}
while(q--){
cin>>op;
if(op==1){
cin>>x1>>y1>>c;
DrawChar(x1,y1,c);
}
else{
cin>>x1>>y1>>x2>>y2;
DrawLine(x1,y1,x2,y2);
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<a[i][j];
}
cout<<endl;
}
return 0;
}
总结
因为模拟题很难找到固定的套路,而且比赛的时候又很容易上头,一般正确率较低。这个题其实属于较为简单的模拟题,找出规律,然后执行BFS即可,但一开始忘了坐标转换的问题,直接BFS板子敲上,一跑样例突然意识到错误(这要是在比赛的时候估计心态要崩),除了需要注意输入坐标与数组下标的关系外,还需要注意填充条件,比如在画 + 时的条件是这个点之前的值与当前要画的线的方向相反或之前已经为 + (这个点做题的时候遗漏了,提交后发现扣了10分才想起来),还有填充字符的时候也要注意覆盖之前所填充的不同字符,总得来说还是要仔细分析题意,防止条件遗漏。