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;
}