CSP-2015-12-3-画图[dfs]

题目描述

用 ASCII 字符来画图是一件有趣的事情,并形成了一门被称为 ASCII Art 的艺术。例如,下图是用 ASCII 字符画出来的 CSPRO 字
样。
   ..____.____..____..____...___..  ./.___/.___||.._.|.._../._..  |.|...___.|.|_).|.|_).|.|.|.|  |.|___.___).|..__/|.._.<|.|_|.|  .____|____/|_|...|_|._\___/.
  本题要求编程实现一个用 ASCII 字符来画图的程序,支持以下两种操作:
  Ÿ 画线:给出两个端点的坐标,画一条连接这两个端点的线段。简便起见题目保证要画的每条线段都是水平或者竖直的。水平线段用字符 - 来画,竖直线段用字符 | 来画。如果一条水平线段和一条竖直线段在某个位置相交,则相交位置用字符 + 代替。
  Ÿ 填充:给出填充的起始位置坐标和需要填充的字符,从起始位置开始,用该字符填充相邻位置,直到遇到画布边缘或已经画好的线段。注意这里的相邻位置只需要考虑上下左右 4 个方向,如下图所示,字符 @ 只和 4 个字符 * 相邻。
  在这里插入图片描述

输入

输出

  输出有n行,每行m个字符,表示依次执行这q个操作后得到的画图结果。

样例输入

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|...
...+--------+...
................

思路

综述

这个题用到了两点:
1)图的搜索遍历;
2)坐标之间的转换

地图问题

因为每个点对于一个字符,所以可以初始化一个较大的二维char数组,初始化为’.’;

坐标转换问题

题目给出的(x,y)转换为字符数组中的(new_x,new_y);
假设图的高度为n,则:
new_x = n-y-1;
new_y = x;

图的遍历

既可以用bfs也可以dfs,比较基础
注意一点:
如下所示,在搜索的过程中注意,到达过,可用如下标记一下,即:到达的点不能是和本字符一样的。

if (ch[x][y] == c)return;
过程
Step1:输入

在输入的时候,进行坐标转换
n为地图的高度

			int x1, y1, x2, y2;
			int newx1, newy1, newx2, newy2;
			cin >> x1 >> y1 >> x2 >> y2;
			newx1 = n - y1;
			newy1 = x1;
			newx2 = n - y2;
			newy2 = x2;
Step2:dfs过程

判断是否能够进行
条件1:已经到达过了(记忆化搜索)

	if (ch[x][y] == c)return;

条件2:触碰到边界

if (x < 0 || y < 0)return;
	if (x > n-1 || y > m-1)return;

条件3:触碰到画的线了

	if((ch[x][y] == '|' || ch[x][y] == '-' || ch[x][y] == '+'))return;

满足上述条件之一,即不能继续进行;当return;
记录

	if (ch[x][y] != '|' && ch[x][y] != '-' && ch[x][y] != '+')
		ch[x][y] = c;

继续往下进行
只有四个方向:上、下、左、右;

	dfs(x + 1, y, c);
	dfs(x - 1, y, c);
	dfs(x, y + 1, c);
	dfs(x, y - 1, c);
Step3:画线问题

只需要一个循环即可:
假定所画的是竖线:
碰到相反方向的线要注意画为‘+’
碰到‘+’或者‘|’都continue

		for (int i = x1; i <= x2; i++) {
			//cout << i;
			if (ch[i][y1] == '+')continue;//碰到‘+’
			else if (ch[i][y1] == '-') ch[i][y1] = '+';
			else if (ch[i][y1] == '|') continue;//碰到'|'
			else ch[i][y1] = '|';
		}

横线上同;

总结

1、图的搜索问题,大多数情况下需要记忆化的搜索,如本题,刚开始没加上下面的语句,导致陷入一种死循环的状态。

	if (ch[x][y] == c)return;

2、坐标的转换问题
可能会遇到题目给出的坐标和数组内的坐标不同的情况,就需要进行如下的转换:
在这里插入图片描述

代码

#include <iostream>
#include <algorithm>

using namespace std;
int m, n, q;
char ch[150][150];

void dfs(int x,int y, char c) {
//剪枝
	if (ch[x][y] == c)return;
	if (x < 0 || y < 0)return;
	if (x > n-1 || y > m-1)return;
	if (ch[x][y] != '|' && ch[x][y] != '-' && ch[x][y] != '+')
		ch[x][y] = c;
	if((ch[x][y] == '|' || ch[x][y] == '-' || ch[x][y] == '+'))return;

	//继续搜索
	dfs(x + 1, y, c);
	dfs(x - 1, y, c);
	dfs(x, y + 1, c);
	dfs(x, y - 1, c);
}

void line(int x1,int y1,int x2,int y2) {
	if (y1 == y2) {
	//画竖线问题
		if (x1 > x2)swap(x1, x2);
		for (int i = x1; i <= x2; i++) {
			//cout << i;
			if (ch[i][y1] == '+')continue;
			else if (ch[i][y1] == '-') ch[i][y1] = '+';
			else if (ch[i][y1] == '|') continue;
			else ch[i][y1] = '|';
		}
	}
	//画横线问题
	else if (x1 == x2) {
		if (y1 > y2)swap(y1, y2);
		for (int i = y1; i <= y2; i++) {
			if (ch[x1][i] == '+')continue;
			else if (ch[x1][i] == '-') continue;
			else if (ch[x1][i] == '|')ch[x1][i] = '+';
			else ch[x1][i] = '-';
		}
	}
}

int main() {
	cin >> m >> n >> q;
	int op;
	
	//初始化地图
	for (int i = 0; i < 150; i++)
		for (int j = 0; j < 150; j++)
			ch[i][j] = '.';

	for (int i = 0; i < q; i++) {
		cin >> op;
		if (op == 0) {
			int x1, y1, x2, y2;
			int newx1, newy1, newx2, newy2;
			cin >> x1 >> y1 >> x2 >> y2;
			//坐标转换
			newx1 = n - y1;
			newy1 = x1;
			newx2 = n - y2;
			newy2 = x2;
			line(newx1-1, newy1, newx2-1, newy2);
		}
		else if (op == 1) {
			int x1, y1;
			int newx1, newy1;
			char x;
			cin >> x1 >> y1;
			cin >> x;
			//坐标转换
			newx1 = n - y1-1;
			newy1 = x1;
			dfs(newx1, newy1, x);
		}
	}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值