题目描述
一张n*m的方格纸,有些格子需要印成黑色,剩下的格子需要保留白色。
你有一个a*b的印章,有些格子是凸起(会沾上墨水)的。你需要判断能否用这个印章印出纸上的图案。印的过程中需要满足以下要求:
(1)印章不可以旋转。
(2)不能把墨水印到纸外面。
(3)纸上的同一个格子不可以印多次。
输入
第一行一个整数q(1<=q<=10),表示测试点数量。
接下来q个测试点,每个测试点中:
第一行包含4个整数n,m,a,b(1<=n,m,a,b<=1000)。
接下来n行,每行m个字符,描述纸上的图案。'.'表示留白,'x'表示需要染黑。
接下来a行,每行b个字符,描述印章。'.'表示不沾墨水,'x'表示沾墨水。
输出
对于每个测试点,输出TAK(是)或NIE(否)。
样例输入
23 4 4 2xx...xx.xx..x..xx...2 2 2 2xxxx.xx.
样例输出
TAKNIE
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
using namespace std;
const int maxn=1003;
struct data{
int x,y;
}add[maxn*maxn];
int n,m,a,b,sum,tot;
char hua[maxn][maxn],ban[maxn][maxn],cpy[maxn][maxn];
bool f[maxn][maxn];
inline int get(){
char c;while(!isdigit(c=getchar()));
int v=c-48;while(isdigit(c=getchar()))v=v*10+c-48;
return v;
}
int main(){
int q=get();
while(q--){
memset(f,0,sizeof(f));
n=get();m=get();a=get();b=get();sum=0;tot=0;
int up,dn,l,r;up=dn=l=r=0;
for(int i=1;i<=n;++i){
scanf("%s",cpy[i]+1);
if(!up)for(int j=1;j<=m;++j)if(cpy[i][j]=='x'){up=i;break;}
}
for(int i=n;i>=up;--i){
if(!dn)for(int j=1;j<=m;++j)if(cpy[i][j]=='x'){dn=i;break;}
if(dn)break;
}
for(int i=1;i<=m;++i){
if(!l)for(int j=1;j<=n;++j)if(cpy[j][i]=='x'){l=i;break;}
if(l)break;
}
for(int i=m;i>=l;--i){
if(!r)for(int j=1;j<=n;++j)if(cpy[j][i]=='x'){r=i;break;}
if(r)break;
}
n=dn-up+1;m=r-l+1;
for(int i=up;i<=dn;++i)for(int j=l;j<=r;++j){
hua[i-up+1][j-l+1]=cpy[i][j];
if(cpy[i][j]=='x')++sum;
}
up=dn=l=r=0;
for(int i=1;i<=a;++i){
scanf("%s",cpy[i]+1);
if(!up)for(int j=1;j<=b;++j)if(cpy[i][j]=='x'){up=i;break;}
}
for(int i=a;i>=up;--i){
if(!dn)for(int j=1;j<=b;++j)if(cpy[i][j]=='x'){dn=i;break;}
if(dn)break;
}
for(int i=1;i<=b;++i){
if(!l)for(int j=1;j<=a;++j)if(cpy[j][i]=='x'){l=i;break;}
if(l)break;
}
for(int i=b;i>=l;--i){
if(!r)for(int j=1;j<=a;++j)if(cpy[j][i]=='x'){r=i;break;}
if(r)break;
}
a=dn-up+1;b=r-l+1;int cnt=0;
for(int i=up;i<=dn;++i)for(int j=l;j<=r;++j){
ban[i-up+1][j-l+1]=cpy[i][j];
if(ban[i-up+1][j-l+1]=='x')add[++cnt].x=i-up,add[cnt].y=j-l;
}
int han=1,lie;
bool flag=1;
if(a>n || b>m)flag=0;
if (flag)while(han<=n){
lie=1;
for(;lie<=m;++lie){
int t=han+add[1].x,s=lie+add[1].y;
if(s>m)break;
if(f[t][s] || hua[t][s]=='.')continue;
if((m-lie+1<b)||(n-han+1<a)){flag=0;break;}
for(int i=1;i<=cnt;++i){
t=han+add[i].x,s=lie+add[i].y;
if(t>n || s>m || f[t][s] || hua[t][s]=='.'){flag=0;break;}
f[t][s]=1;++tot;
}
if(!flag)break;
}
if(!flag)break;
++han;
}
if(tot!=sum)flag=0;
if(!flag)printf("NIE\n");
else printf("TAK\n");
}
return 0;
}
思路:把章和画的空白边框去掉。枚举画的一点作为左上角,边界什么的处理一下。用sum记录画中x的总数,用tot记录盖上去x的总数,最后要判断sum==(!=)tot。
注意:注意一些细节的判断。