P7411 [USACO21FEB] Comfortable Cows S 题解
谷首A
Description
坐标轴有 \(k\) 个点,加入一些点使得没有点的周围有三个点(包括新加的点),最小化加点个数。
Solution
模拟+贪心
只要周围有三个点,就加入一个点,然后我们知道,新加进来点之后,只会影响新点和新点四周的点,所以我们可以再检查四周的点是否满足条件即可。
至于如何检验:只要统计一下这个点四周有没有被标记就可以。
关于检验负数点:我的处理方法是给坐标加上一个数,避免出现负数。
Code
#include<iostream>
#include<algorithm>
using namespace std;
inline int Read(){
int s = 0 , w = 1;
char ch = getchar();
while(ch > '9' || ch < '0'){
if(ch == '-') w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
s = (s << 3) + (s << 1) + ch - '0';
ch = getchar();
}
return s * w;
}
const int MAXN = 2e5 + 50;
int n,ans;
int x[MAXN],y[MAXN];
int s[5000][5000];
int mx[] = {0,1,0,-1};
int my[] = {1,0,-1,0};
bool check(int a,int b){
if(!s[a][b]) return false;
int tmp = 0;
for(int d = 0 ; d < 4 ; d ++){
if(s[a + mx[d]][b + my[d]]) tmp ++;
}
return tmp == 3;
}//检验四周是否有三个点
void mod(int a,int b){
for(int d = 0 ; d < 4 ; d ++){
int xx = a + mx[d] , yy = b + my[d];
if(s[xx][yy] == 0){
s[xx][yy] = 2;
ans ++;
if(check(xx,yy)) mod(xx,yy);
for(int dd = 0 ; dd < 4 ; dd ++){
if(check(xx + mx[dd],yy + my[dd])) mod(xx + mx[dd],yy + my[dd]);
}//修改时如果导致新点满足条件,则还要修改新点
}
}
}
int main(){
n = Read();
for(int i = 1 ; i <= n ; i ++){
x[i] = Read() + 1000, y[i] = Read() + 1000;
}
for(int i = 1 ; i <= n ; i ++){
if(s[x[i]][y[i]] == 2) ans --;
s[x[i]][y[i]] = 1;
if(check(x[i],y[i])) mod(x[i],y[i]);
for(int d = 0 ; d < 4 ; d ++){
if(check(x[i] + mx[d],y[i] + my[d])) mod(x[i] + mx[d],y[i] + my[d]);
}
printf("%d\n",ans);
}
return 0;
}