C++:广搜基础例题:填涂颜色

广度优先搜索例题:填涂颜色

1.题目

洛谷P1162

题目描述
由数字0组成的方阵中,有一任意形状闭合圈,闭合圈由数字1构成,围圈时只走上下左右4个方向。现要求把闭合圈内的所有空间都填写成2。例如:6×6的方阵(n=6),涂色前和涂色后的方阵如下:
填涂前
填涂后
输入格式
每组测试数据第一行一个整数 (1≤n≤30)
接下来n行,由0和1组成的 n×n 的方阵。
方阵内只有一个闭合圈,圈内至少有一个0。
输出格式
已经填好数字22的完整方阵。

输入

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

2.题解

源码如下:

#include <iostream>
using namespace std;
int a[32][32], b[32][32];
int dx[5] = { 0,-1,1,0,0 };
int dy[5] = { 0,0,0,-1,1 };
int n, i, j;
void dfs(int p, int q) {
	int i;
	if (p<0 || p>n + 1 || q<0 || q>n + 1 || b[p][q] != 0) 
		return;
	b[p][q] = 1;
	for (i = 1; i <= 4; i++) 
		dfs(p + dx[i], q + dy[i]);
}
int main() {
	cin >> n;
	for (i = 1; i <= n; i++)
		for (j = 1; j <= n; j++) {
			cin >> a[i][j];
			if (a[i][j] == 0) 
				b[i][j] = 0;
			else b[i][j] = 1;
		}
	dfs(0, 0);
	for (i = 1; i <= n; i++) {
		for (j = 1; j <= n; j++)
			if (b[i][j] == 0) 
				cout << 2 << ' ';
			else 
				cout << a[i][j] << ' ';
		cout << '\n';
	}
}

思路引导:
应该是不难看出来这是一道基础的广度优先搜索的题目,也就是BFS,问题的本质就是将墙内的值分开,至于墙和墙外,我们按照原来输出就可以。首先我们将二维数组数据储存在二维数组a中,有一点需要注意就是,不能从(0,0)开始存,从(0,0)开始存的话,在后面搜索进行的时候,会出现数组越界的问题,另外定义另一个数组b用来表示我们01图的各个元素的状态,如果是a对应的位置是墙,则将b对应位置染色为1,反之染色为0。

	for (i = 1; i <= n; i++)
		for (j = 1; j <= n; j++) {
			cin >> a[i][j];
			if (a[i][j] == 0) 
				b[i][j] = 0;
			else b[i][j] = 1;
		}

然后从(0,0)出发,开始遍历搜索,如果遇到墙,或者到达数组的边界,才返回。

if (p<0 || p>n + 1 || q<0 || q>n + 1 || b[p][q] != 0) 
		return;

如果没有返回,也就是这个位置对应数组a的值为0,即不为墙且不为墙内,然后对这个位置进行染色,其实就是将墙外的位置也变置为墙,这一步染色很重要,如果没有染色,在进入下一个位置后,程序往上下左右进行遍历时,没有标志能提示给程序上一个位置是否已经被遍历过了,程序就会再一次进入之前遍历过的那个位置,也即又回到了(0,0),这也是我同学之前遇到的问题,始终无法跳出函数。

void dfs(int p, int q) {
	int i;
	if (p<0 || p>n + 1 || q<0 || q>n + 1 || b[p][q] != 0) 
		return;
	b[p][q] = 1;
	for (i = 1; i <= 4; i++) 
		dfs(p + dx[i], q + dy[i]);
}

接着就是上一步说的,在初始位置染色后,我们往上下左右(通过两个数组实现)四个方向进行遍历,每次遍历一个方向,就相当于再次跳进一个位置的bfs函数中,递归,一直到所有的非墙内的位置都被遍历并且染色,变置为墙。
此时在数组b中,除了值为0点位置,其他位置都变置为墙了,也就是,除了墙内的位置,其他位置都为1,那么问题也就解决了,输出:

for (i = 1; i <= n; i++) {
		for (j = 1; j <= n; j++)
			if (b[i][j] == 0) 
				cout << 2 << ' ';
			else 
				cout << a[i][j] << ' ';
		cout << '\n';
	}

3.小结

总的来说,题目是一道比较为基础的广搜题,而最为主要的地方就是,定义另一个数组复刻原来的数组,对这个数组进行染色,区分出要改变值的地方。
对于不需要改变的按照a数组原样输出,对于要改变的,通过b数组识别判断,输出题目要求的对应值,也就完成啦。
题目本身也是不太难,希望能帮到刚要学习广度搜索的同学,谢谢浏览啦!

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值