P3751. 填涂颜色

先介绍Flood fill算法。

Flood Fill算法

洪水填充(Flood fill)算法:从一个起始节点开始把附近与其连通的节点提取出或填充成不同颜色颜色,直到封闭区域内的所有节点都被处理过为止,是从一个区域中提取若干个连通的点与其他相邻区域区分开(或分别染成不同颜色)的经典算法。

本题思路

因为对任意形状闭合圈,闭合圈由数字 1构成。所以,这题可以用上面的flood fill算法,将整个边界进行搜索,将圈外的0进行判定。之后,遍历整个空间,根据0和1的判定进行输出即可。

代码

void solve() {
    int n; cin>>n; // 输入
    vector<vector<int>> ph(n, vector<int>(n)); // vector存 n * n 的空间
    auto vis(ph); // vis数组对0进行判定,如果为 1, 表示这是圈外零,否则为 0, 表示圈内的零
    for(auto &tt: ph) { // 读入
        for(auto &t: tt) cin>>t;
    }
    vector<int> fx({0,0,1,-1}), fy({1,-1,0,0}); // 四个方向
    auto dfs = [&](auto&& dfs, int x, int y) -> void { // dfs
        if(vis[x][y]) return ; // 如果已经访问过,return
        vis[x][y] = 1; // 否则,设置将该位置设置为1
        for(int i = 0; i < 4; ++i) { // 对四个方向进行搜索
            int xx = x + fx[i], yy = y + fy[i];
            if(xx < 0 || xx >= n || yy < 0 || yy >= n) continue; // 如果超出边界,就continue
            if(vis[xx][yy]) continue; // 如果这个位置之前访问过,continue
            if(ph[xx][yy]) continue; // 如果这个位置是1,也continue
            dfs(dfs,xx,yy); 
        }
    };
    // 对边进行搜索,将外围的0的vis数组置为 1
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            if(ph[i][j] == 1) continue;
            if(i == 0 || j == 0) dfs(dfs, i,j);
            if(i == n-1 || j == n-1) dfs(dfs, i,j);
        }
    }
    // 输入
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            int k = 0;
            if(ph[i][j]) k = 1; // 如果是1,则为1,不变
            else if(vis[i][j]) k = 0; // 如果为0,且这个访问过,为0
            else k = 2; // 否则,表示该0是圈内0,设置为2
            cout<<k<<" ";
        } puts("");
    }
}

你可能感兴趣的:(算法题,深度优先,算法)