zoukankan      html  css  js  c++  java
  • 洛谷P3585 [POI2015]PIE

    传送门

    题目大意:有个n*m的格子图,要求'x'点要被染成黑色

    有个a*b的印章,'x'是可以染色的印章上的点。

    要求用印章去染色格子

    (1)印章不可以旋转。

    (2)不能把墨水印到纸外面。

    (3)纸上的同一个格子不可以印多次。

    题解:模拟

    从题目中可以看出,一定要让印章的左上角对应目前n*m方

    格中未染色的左上角。因为要求不能重复染色,可以每染完

    一个格子就把它赋值为0.(待染色为1)。

    开始纯模拟,没有任何优化的代码。

    加了个读入优化还是T了两个点,3000ms+

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 1022
    using namespace std;
    int n,m,a,b,fa,fb,cnt,q;
    int map[N][N],yz[N][N];
    char s[N];
    inline int read(int &x){
        char ch=getchar();x=0;int f=1;
        for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
        x=x*f;
    }
    void init(){
        memset(map,0,sizeof(map));
        memset(yz,0,sizeof(yz));
        cnt=0;fa=0;fb=0;
    }
    bool check(int x,int y){
        int xx=x-fa,yy=y-fb;
        for(int i=1;i<=a;i++){
            for(int j=1;j<=b;j++){
                if(yz[i][j]==0)continue;
                int rx=xx+i,ry=yy+j;
                if(rx<0||ry<0||rx>n||ry>m||map[rx][ry]==0)return false;
                map[rx][ry]=0;cnt--;
            }
        }
        return true;
    }
    int main(){
        scanf("%d",&q);
        while(q--){
            init();bool flag=false;
           // scanf("%d%d%d%d",&n,&m,&a,&b);
          //  n=read();m=read();a=read();b=read();
           read(n);read(m);read(a);read(b);
            for(int i=1;i<=n;i++){
                scanf("%s",s+1);
                for(int j=1;j<=m;j++)
                 if(s[j]=='x')map[i][j]=1,cnt++;
            }
            for(int i=1;i<=a;i++){
                scanf("%s",s+1);
                for(int j=1;j<=b;j++){
                    if(s[j]=='.')continue;
                    if(!fa&&!fb)fa=i,fb=j;
                    yz[i][j]=1;
                }
            }
            for(register int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    if(map[i][j]){
                        if(check(i,j)==0){
                            printf("NIE
    ");
                            flag=true;break;
                        }
                        if(cnt==0){
                            printf("TAK
    ");
                            flag=true;break;
                        }
                    }
                }
                if(flag)break;
            }
        }
        return 0;
    }
    80

    看了题解... 想到以前做靶型数独这个题,把未填数的格子放到一个结构体里。

    w[i].x,w[i].y分别表示第i个没有填数格子的横纵坐标。

    这样的好处是不用遍历整张图,就找到了没填数的格子。

    这个题也是这样....

    上面的代码不仅遍历了一遍要染色的图,还遍历了整个印章。

    最差的情况是10^12...遍历要染色的10^6,印章10^6。

    所以把要染色的点和能染色的点抽离出来,放到结构体里。

    很好的一个优化,188ms。

    ps:某一行后面+***,可以这样理解..

    yz[1].x+xx=x,yz[1].y+yy=y.

    说明印章的左上角的可以染色的点,要对应

    n*m的棋盘要加xx和yy,那么其他可以染色的点也要加这两个数

    来对应他们要染色的点。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 1009
    using namespace std;
    int n,m,a,b,cnt_black,yz_black,q;
    char s[N];
    int map[N][N];
    struct Make_Black{
        int x,y;
    }gz[N*N],yz[N*N];
    bool check(int x,int y){
        int xx=x-yz[1].x,yy=y-yz[1].y;  //*** 
        for(int i=1;i<=yz_black;i++){  
            int nx=yz[i].x+xx,ny=yz[i].y+yy;
            if(nx<0||nx>n||ny<0||ny>m||map[nx][ny]==0)return false;
            map[nx][ny]=false;
        }
        return true;
    }
    int main(){
        scanf("%d",&q);
        while(q--){
            bool flag=false;
            cnt_black=yz_black=0;
            scanf("%d%d%d%d",&n,&m,&a,&b);
            memset(map,0,sizeof(map));
            for(int i=1;i<=n;i++){
                scanf("%s",s+1);
                for(int j=1;j<=m;j++)
                 if(s[j]=='x'){
                     gz[++cnt_black].x=i;gz[cnt_black].y=j;
                     map[i][j]=true;
                 }
            }
            for(int i=1;i<=a;i++){
                scanf("%s",s+1);
                for(int j=1;j<=b;j++)
                 if(s[j]=='x')yz[++yz_black].x=i,yz[yz_black].y=j;
            }
            for(int i=1;i<=cnt_black;i++){
                if(map[gz[i].x][gz[i].y])
                 if(check(gz[i].x,gz[i].y)==0){
                     flag=true;
                     printf("NIE
    ");break;
                 }
            }
            if(!flag)printf("TAK
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    bzoj1854 [Scoi2010]游戏
    bzoj2456 mode
    bzoj4810 [Ynoi2017]由乃的玉米田
    bzoj1076 [SCOI2008]奖励关
    bzoj3064 Tyvj 1518 CPU监控
    bzoj1798 [Ahoi2009]维护序列
    bzoj3575 [Hnoi2014]道路堵塞
    bzoj3992 [SDOI2015]序列统计
    uoj#34. 多项式乘法
    高等代数典型问题集
  • 原文地址:https://www.cnblogs.com/zzyh/p/7788275.html
Copyright © 2011-2022 走看看