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;
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章