画图(CSP 201512 03):
问题描述
题目简述
本题要求编程实现一个用 ASCII 字符来画图的程序,支持以下两种操作:
画线:给出两个端点的坐标,画一条连接这两个端点的线段。简便起见题目保证要画的每条线段都是水平或者竖直的。水平线段用字符 - 来画,竖直线段用字符 | 来画。如果一条水平线段和一条竖直线段在某个位置相交,则相交位置用字符 + 代替。
填充:给出填充的起始位置坐标和需要填充的字符,从起始位置开始,用该字符填充相邻位置,直到遇到画布边缘或已经画好的线段。注意这里的相邻位置只需要考虑上下左右 4 个方向。
输入/输出格式
输入格式:
第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个操作按照数据给出的顺序依次执行。画布最初时所有位置都是字符 .(小数点)。
输出格式:
输出有n行,每行m个字符,表示依次执行这q个操作后得到的画图结果。
样例
输入样例:
4 2 3
1 0 0 B
0 1 0 2 0
1 0 0 A
输出样例:
AAAA
A----A
问题分析
解题思路
CSP的第三题一般考察的都是比较大的模拟题。而这道题算是比较“平易近人”的一道题了。至少对我而言,读完一遍题基本能把题目读懂了。(相比于最近两年CSP的第三题的配置而言,这道题已经很不错了)言归正传,这个题的思路很明确,要求完成画线和填充。思路也比较常规,就是开一个二维数组来表示画布,之后初始化完了根据操作来执行就完了。接下来具体的来说一下各操作的写法:
1.画线:
这个还是很好写的,题目中只要求完成画水平线和竖直线,那就根据输入的数据到底是x不同还是y不同分开写代码就可以了。流程也差不多:找到初始位置和结束位置(这里需要统一,比如让小的数作为起点,大的数作为终点),判断位置上是需要填充还是需要替换成“+”还是跳过就没别的东西了。
2.填充:
填充最重要的还是怎么找到相邻位置。这个题相邻位置是某个点的上下左右四个位置。那么它们和这个点的关系就是要么x坐标改变1,要么y坐标改变1,两者不能同时改变。这样用两个长度为4的常量数组即可表示4个方向。方法是常规的bfs,再开一个相同大小的标记数组然后用队列辅助bfs就可以完成了。
参考代码(100分)
评测截图如下:
#include <cstdio>
#include <cmath>
#include <queue>
using namespace std;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int main()
{
int m,n,q;
scanf("%d %d %d",&m,&n,&q);
char **paper;
paper=new char*[n];
for(int i=0;i<n;i++)
{
paper[i]=new char[m];
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
paper[i][j]='.';
}
}
for(int k=1;k<=q;k++)
{
int op;
scanf("%d",&op);
if(op==0)
{
int x1,y1,x2,y2;
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
if(x1==x2)
{
int start,end;
if(y1<y2)
{
start=y1;
end=y2;
}
else
{
start=y2;
end=y1;
}
for(int i=start;i!=end+1;i++)
{
if(paper[i][x1]=='-')
{
paper[i][x1]='+';
}
else if(paper[i][x1]=='|'||paper[i][x1]=='+') continue;
else
{
paper[i][x1]='|';
}
}
}
else
{
int start,end;
if(x1<x2)
{
start=x1;
end=x2;
}
else
{
start=x2;
end=x1;
}
for(int i=start;i!=end+1;i++)
{
if(paper[y1][i]=='|')
{
paper[y1][i]='+';
}
else if(paper[y1][i]=='-'||paper[y1][i]=='+') continue;
else
{
paper[y1][i]='-';
}
}
}
//画线
}
else
{
int sx,sy;
char tag;
scanf("%d %d %c",&sx,&sy,&tag);
queue<int> tx;
queue<int> ty;
tx.push(sx);
ty.push(sy);
paper[sy][sx]=tag;
int **reach;
reach=new int*[n];
for(int i=0;i<n;i++)
{
reach[i]=new int[m];
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
reach[i][j]=0;
}
}
reach[sy][sx]=1;
while(!tx.empty())
{
int x=tx.front();
int y=ty.front();
//printf("basic:(%d,%d)\n",x,y);
for(int i=0;i<4;i++)
{
if(x+dx[i]>=0&&x+dx[i]<m&&y+dy[i]>=0&&y+dy[i]<n)
{
//printf("try find(%d,%d),the message:paper:%c,reach:%d\n",x+dx[i],y+dy[i],paper[y+dy[i]][x+dx[i]],reach[y+dy[i]][x+dx[i]]);
if(paper[y+dy[i]][x+dx[i]]!='-'&&paper[y+dy[i]][x+dx[i]]!='|'&&paper[y+dy[i]][x+dx[i]]!='+'&&reach[y+dy[i]][x+dx[i]]==0)
{
//printf("position:(%d,%d) is OK\n",x+dx[i],y+dy[i]);
paper[y+dy[i]][x+dx[i]]=tag;
tx.push(x+dx[i]);
ty.push(y+dy[i]);
reach[y+dy[i]][x+dx[i]]=1;
}
}
}
tx.pop();
ty.pop();
}
//填充
}
}
for(int i=n-1;i>=0;i--)
{
for(int j=0;j<m;j++)
{
printf("%c",paper[i][j]);
}
if(i!=0) printf("\n");
}
return 0;
}
心得体会
这个题虽然看上去比较长,但实际做的话就会发现,这个题其实很基础,考察的知识点也很常规。总之在模拟题中也算比较简单的吧。自我感觉做的还是比较顺利的,除了在数组的横纵坐标对应的时候,由于前后程序不一致导致调代码的时间有点长。(捂脸,真丢人)其他的感觉还是很顺的。总之,一道比较基础的模拟题,拿来练手感觉很不错。