2422 Pieczęć(pie)(模拟)

本文介绍了一种判断特定印章是否能完整印制出指定图案的算法。该算法通过预处理图案和印章,去除多余空白并逐个匹配图案中的元素来验证可行性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

一张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。

注意:注意一些细节的判断。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值