ACM训练集---洛谷 P1162 填涂颜色

题目描述

由数字0组成的方阵中,有一任意形状闭合圈,闭合圈由数字1构成,围圈时只走上下左右4个方向。现要求把闭合圈内的所有空间都填写成2.例如:6×6的方阵(n=6n=6),涂色前和涂色后的方阵如下:

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1

输入格式

每组测试数据第一行一个整数n(1≤n≤30)

接下来n行,由0和1组成的n×n的方阵。

方阵内只有一个闭合圈,圈内至少有一个0。

输出格式

已经填好数字2的完整方阵。


输入输出样例
输入

6
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1

输出

0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1

说明/提示:1 ≤ n ≤ 30


解题思路:

  1. 难点1:我们不太好判断0有没有被1所围住,所以我们需要换一种思路,看能不能找出没有被1围住的0,并对他们做上标记,例如将0变成2;此时我们可以从第一个没有被围住的0开始,一直遍历每个点,遇到0就将其变成2,遇到1或2就返回,最后剩下的0就是被围住的0
  2. 难点2:因为我们不知道 第一个没有被围住的0 会出现在哪个位置,所以我们不能很方便的从某一个点开始遍历。此时我们可以扩大该矩阵,即在矩阵的四周都加上0,这样我们就可以保证在i=0,j=0的位置是没有被1围住的
  3. 扩展:本题的遍历方式可以有深度优先遍历(DFS)和 广度优先遍历(BFS)。在文章最后会总结两者的一些区别。

AC代码—DFS方式

#include<iostream>

using namespace std;

int n, a[32][32];

void dfs(int i, int j){
	int x[4] = { 0, 0, 1, -1 }, y[4] = { 1, -1, 0, 0 };
	// 添加标记
	a[i][j] = 2;
	for (int k = 0; k < 4; k++){
		// 遍历每个方向
		int xx = i + x[k], yy = j + y[k];
		// 判断有无出界 下一步是否为1或2
		// 1代表不能走,2代表走过了
		if (xx >= 0 && xx <= n + 1 && yy >= 0 && yy <= n + 1 && a[xx][yy] != 1 && a[xx][yy] != 2){
			dfs(xx, yy);
		}
	}
}

int main(){
	int i, j;
	cin >> n;
	cin.get();
	for (i = 1; i <= n; i++){
		for (j = 1; j <= n; j++){
			cin >> a[i][j];
		}
	}
	// C++开数组时元素的值默认是0,这两个for可省略
	for (j = 0; j <= n + 1; j++){
		// 扩展首行跟尾行
		a[0][j] = 0; a[n + 1][j] = 0;
	}
	for (i = 0; i <= n + 1; i++) {
		// 扩展首列跟尾列
		a[i][0] = 0; a[i][n + 1] = 0;
	}

	dfs(0, 0);

	for (i = 1; i <= n; i++){
		for (j = 1; j <= n; j++){
			switch (a[i][j])
			{
			case 1:cout << 1 << " "; break;
			case 2:cout << 0 << " "; break;
			case 0:cout << 2 << " "; break;
			}
		}
		cout << endl;
	}
	return 0;
}

AC代码—BFS方式

#include<iostream>
#include<queue>
using namespace std;

int n, a[32][32];

struct point
{
	int x, y;
};

void bfs(){
	queue<point> q;
	point p;
	p.x = 0; p.y = 0; 
	a[0][0] = 2; // 做标记
	while (!q.empty()){
		point t = q.front();
		q.pop();
		// 方向
		int x[4] = { 0, 0, -1, 1 }, y[4] = { -1, 1, 0, 0 };
		// 每个方向都遍历一次
		for (int i = 0; i < 4; i++){
			// 下个搜索方向的坐标
			int xx = t.x + x[i], yy = t.y + y[i];
			if (xx >= 0 && xx <= n + 1 && yy >= 0 && yy <= n + 1 && a[xx][yy] != 1 && a[xx][yy] != 2){
				point p;
				p.x = xx; p.y = yy; 
				a[xx][yy] = 2;
				q.push(p); 
			}
		}
	}
}

int main(){
	int i, j;
	cin >> n;
	cin.get();
	for (i = 1; i <= n; i++){
		for (j = 1; j <= n; j++){
			cin >> a[i][j];
		}
	}
	bfs();
	for (i = 1; i <= n; i++){
		for (j = 1; j <= n; j++){
			switch (a[i][j])
			{
			case 1:cout << 1 << " "; break;
			case 2:cout << 0 << " "; break;
			case 0:cout << 2 << " "; break;
			}
		}
		cout << endl;
	}
	return 0;
}

两者的运行效率如图:(24ms的是DFS,22ms的是BFS)
在这里插入图片描述


总结:

  1. BFS比DFS代码更多一些,所需的空间多一些,但BFS所需的时间比较少,性能感觉也比较好。
  2. BFS一般与队列queue挂钩,因为他是从一层层遍历的。

tips:

DFS有个致命缺点,如果深度很深,就会出现栈溢出,或者超时的情况。(因为有些题目就会卡DFS的深度,比如让你在10W*10的矩阵中找一个元素,而该元素就在矩阵的前部分,但此时DFS就会一直搜索到10W深的地方,而BFS一下子就可以找到该元素了)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值