广度优先搜索例题:填涂颜色
1.题目
题目描述
由数字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数组识别判断,输出题目要求的对应值,也就完成啦。
题目本身也是不太难,希望能帮到刚要学习广度搜索的同学,谢谢浏览啦!