PKU3363 Annoying painting tool - 超级构造法

来源:互联网 发布:java 动态添加属性 编辑:程序博客网 时间:2024/06/09 18:11

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

原创粉丝点击