P1162 填涂颜色

题目理解

这道题目要求我们在一个由0和1组成的方阵中,找到由1构成的闭合圈,并将闭合圈内的所有0替换为2。闭合圈的定义是:如果一个0无法通过上下左右移动(仅经过其他0)到达方阵的边界,那么这个0就在闭合圈内。

解题思路

这道题的解题思路可以概括为"逆向思维":

  1. 边界0的标记:首先,我们遍历方阵的四条边,找到所有边界上的0,然后从这些0出发进行广度优先搜索(BFS),标记所有能够从边界到达的0(这些0不在闭合圈内)。

  2. 区分内外0:标记完成后,剩下的未被标记的0就是闭合圈内部的0,需要将它们改为2。

  3. 恢复边界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;
}

 

posted @ 2025-05-22 11:21  行胜于言Ibl  阅读(14)  评论(0)    收藏  举报