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
  • 相关阅读:
    73. Set Matrix Zeroes
    289. Game of Live
    212. Word Search II
    79. Word Search
    142. Linked List Cycle II
    141. Linked List Cycle
    287. Find the Duplicate Number
    260. Single Number III
    137. Single Number II
    Oracle EBS中有关Form的触发器的执行顺序
  • 原文地址:https://www.cnblogs.com/zzyh/p/7788275.html
Copyright © 2011-2022 走看看