BNUEP1202 PKU3363 Annoying painting tool
题目大意:
一个N×M的图片(N,M<100),每个点只有01两种状态。现在有一个R×C的画图工具(R<N,C<M),画一次能将矩形区域内的所有点状态翻转。初始时所有点都是0,现在给出一种目标图片,问最少需要几笔能画出来。
分析:
题目描述看似搜索,其实可以用一个超级构造法直接得出结果。
首先有一个很显然的限制条件:画笔在同一个位置最多画一次。
原因很简单,若在同一位置画两次和不画是等价的。
考虑最左上角的一个点,只有当画笔放在最左上角的时候才能改变其状态。若该点和目标图片一致,则不用画;否则需要在这个点的地方画一笔,同时将矩形其他点的状态翻转。
然后考虑左上角的第二个点,同样地,由于影响该点的画笔只有两个位置,而第一个位置刚才已经确定了,根据该点的状态也能确定是否要在第二个点使用画笔……
总的来说,依次确定从左上到右下的每一个点,若该点与目标图片不一致,则必然在该点使用一次画笔;否则不用。
注意处理不能画出目标图片的情况。
花絮:
几年前高中那次NOI省队选拔冬令营的时候遇到一个及其类似的题目。大意是说一个2×N的棋盘上玩扫雷游戏,其中有一行确定了没有地雷且给出了“该点周围有多少地雷”的状态;另一行则是未知区域。最后要求给出的信息是否存在矛盾。
===================================================
/*
PKU3363 Annoying painting tool
*/
#include <stdio.h>
#include <string.h>
#define clr(a) memset(a,0,sizeof(a))
#define N 101
int main()
{
int i,j,k,m,n,x,y;
int s,r,c,count,flag;
char a[N][N];
char b[N][N];
while(scanf("%d%d%d%d",&n,&m,&r,&c),n||m||r||c){
//input
getchar();
for(i=0;i<n;i++){
scanf("%s",&a[i]);
for(j=0;j<m;j++) a[i][j]=a[i][j]=='0'?0:1;
}
//work
count=0; clr(b);
for(i=0;i<n-r+1;i++){
for(j=0;j<m-c+1;j++){
if(a[i][j]!=b[i][j]){
count++;
for(x=0;x<r;x++) for(y=0;y<c;y++)
b[i+x][j+y]=!b[i+x][j+y];
}
}
}
//judge
flag=1;
for(i=n-1;i>=0&&flag;i--)
for(j=m-1;j>=0&&flag;j--){
if(a[i][j]!=b[i][j])
flag=0;
}
if(!flag) puts("-1");
else printf("%d/n",count);
}
return 0;
}