CF525D Arthur and Walls(贪心染色)题解

细节题

本文会把作者踩到的坑指出,以便您调试

思路

贪心+\(DFS\)染色,算法其实很好想,考虑哪些\(*\)点是必须被替换的:

通过观察,我们发现,一个\(*\)点要被替换,当且仅当有一个包含它的\(2\times 2\)的矩阵中除它之外全是\(.\)点(当我们已经将其他需要替换的\(*\)点替换掉时)

证明:当一个\(*\)点联通块需要被替换时,块内必然有一个\(*\)点被\(.\)点半包围(因为只有这样它才会阻碍\(.\)点组成矩形),于是我们将改点替换成\(.\)点。不难发现,块内剩下的\(*\)点又可以通过同样的方式判断

  • \(DFS\)每次应向周围\(8\)个点拓展;
  • 判断半包围时请老老实实列举每一种情况;
  • 判断或拓展新点时应确保其在图内
  • 只能\(*\)\(.\)不能反过来换

代码

#include <bits/stdc++.h>

using namespace std;

int n,m;
char a[2020][2020];
int mx[8] = {0, 1, -1, 0, 1, -1, -1, 1};
int my[8] = {1, 0, 0, -1, 1, -1, 1, -1};

int check(int x, int y){
    if(x < 1 || x > n) return 0;
    if(y < 1 || y > m) return 0;
    return (a[x][y] == '.');
}

int exam(int i, int j){
    if(check(i - 1, j) && check(i, j - 1) && check(i - 1, j - 1)) return 1;
    if(check(i - 1, j) && check(i, j + 1) && check(i - 1, j + 1)) return 1;
    if(check(i + 1, j) && check(i, j - 1) && check(i + 1, j - 1)) return 1;
    if(check(i + 1, j) && check(i, j + 1) && check(i + 1, j + 1)) return 1;
    return 0;
}

void DFS(int x, int y){
    for(int i = 0; i < 8; ++ i){
        int nx = x + mx[i];
        int ny = y + my[i];
        if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && a[nx][ny] == '*' && exam(nx, ny))
            a[nx][ny] = '.', DFS(nx, ny);
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for(int i = 1; i <= n; ++ i)
        for(int j = 1; j <= m; ++ j) 
            cin >> a[i][j];
    
    for(int i = 1; i <= n; ++ i)
        for(int j = 1; j <= m; ++ j)
            if(a[i][j] == '*'){
                if(exam(i, j)) a[i][j] = '.', DFS(i, j);
            }    
    
    for(int i = 1; i <= n; ++ i){
        for(int j = 1; j <= m; ++ j)
            cout << a[i][j];
        cout << endl;
    }
    return 0;
}
posted @ 2020-10-22 09:34  When_C  阅读(100)  评论(0编辑  收藏  举报