P1162 填涂颜色
题目理解
这道题目要求我们在一个由0和1组成的方阵中,找到由1构成的闭合圈,并将闭合圈内的所有0替换为2。闭合圈的定义是:如果一个0无法通过上下左右移动(仅经过其他0)到达方阵的边界,那么这个0就在闭合圈内。
解题思路
这道题的解题思路可以概括为"逆向思维":
-
边界0的标记:首先,我们遍历方阵的四条边,找到所有边界上的0,然后从这些0出发进行广度优先搜索(BFS),标记所有能够从边界到达的0(这些0不在闭合圈内)。
-
区分内外0:标记完成后,剩下的未被标记的0就是闭合圈内部的0,需要将它们改为2。
-
恢复边界0:最后,将之前标记为"3"的边界可达0恢复为0,保持1不变,输出最终结果。
这种方法巧妙地避开了直接寻找闭合圈的困难,转而通过标记外部可达区域来间接确定内部区域。
参考程序
#include<bits/stdc++.h>
#define N 35 // 定义方阵的最大尺寸
#define endl "\n"
using namespace std;
// 定义坐标结构体
struct node {
int x, y;
};
int G[N][N]; // 存储方阵数据
bool vis[N][N]; // 标记数组,记录是否访问过
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; // 四个方向的移动增量
int n; // 方阵大小
queue<node> q; // BFS使用的队列
// 广度优先搜索函数,从(x,y)出发标记所有可达的0
void bfs(int x, int y) {
node s = {x, y}; // 起点
vis[x][y] = 1; // 标记为已访问
G[x][y] = 3; // 将边界可达的0临时标记为3
q.push(s); // 入队
while (!q.empty()) {
s = q.front();
// 检查四个方向
for (int i = 0; i < 4; i++) {
int xx = s.x+dx[i], yy = s.y+dy[i];
// 如果新位置在方阵内、是0且未被访问过
if (xx >= 1 && xx <= n && yy >= 1 && yy <= n && G[xx][yy] == 0 && vis[xx][yy] == 0) {
vis[xx][yy] = 1; // 标记为已访问
G[xx][yy] = 3; // 临时标记为3
node t = {xx, yy};
q.push(t); // 入队继续搜索
}
}
q.pop();
}
}
int main() {
cin >> n; // 输入方阵大小
// 输入方阵数据
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> G[i][j];
if (G[i][j] == 1) vis[i][j] = 1; // 1的位置标记为已访问(不需要处理)
}
}
// 处理四条边上的0
// 上边
for (int i = 1; i <= n; i++) {
if (G[1][i] == 0) bfs(1, i);
}
// 下边
for (int i = 1; i <= n; i++) {
if (G[n][i] == 0) bfs(n, i);
}
// 左边
for (int i = 1; i <= n; i++) {
if (G[i][1] == 0) bfs(i, 1);
}
// 右边
for (int i = 1; i <= n; i++) {
if (G[i][n] == 0) bfs(i, n);
}
// 输出结果
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (G[i][j] == 3) cout << 0 << " "; // 恢复边界可达的0
else if (G[i][j] == 0) cout << 2 << " "; // 内部0改为2
else cout << 1 << " "; // 保持1不变
}
cout << endl;
}
return 0;
}

浙公网安备 33010602011771号