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;
}
posted @ 2021-04-08 19:58  feicheng  阅读(392)  评论(0编辑  收藏  举报