week5——实验(月模拟题1:CSP 201512 03)

画图(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;
}

心得体会

这个题虽然看上去比较长,但实际做的话就会发现,这个题其实很基础,考察的知识点也很常规。总之在模拟题中也算比较简单的吧。自我感觉做的还是比较顺利的,除了在数组的横纵坐标对应的时候,由于前后程序不一致导致调代码的时间有点长。(捂脸,真丢人)其他的感觉还是很顺的。总之,一道比较基础的模拟题,拿来练手感觉很不错。

发布了10 篇原创文章 · 获赞 1 · 访问量 171

猜你喜欢

转载自blog.csdn.net/qq_43715114/article/details/104982590