题意:
给定一个边长分别为n,m(m<=n)的正方形图,考虑大图(边长为n)中的图形(由'*'构成的部分),能否由两个小图中的图形构成,注意小图中的图形不能旋转,只能平移。
题目链接:Polyomino Composer
解题思路;
因为小图的图形只能平移去拼,所以直接同时取大,小图中最左上脚的位置,从这个位置开始尝试消除大图中的'*',
如果此处小图中是’*‘,但大图不是,那就肯定不能拼了
如果小图中的’*‘数量为cnt,而此时大图中消除的’*‘ 小于cnt ,那也是不能拼了
如果拼了两个小图了,大图还有’*‘也是不符合,用一个小图拼也不符合(被坑了)
还有,我们开始消除的点是最左上脚的,但小图中可能在中间会有一个凸起来的部分,比如:
*
***
所以只能把大图都给便利一遍(反正长宽很小)
代码:
#include<cstdio>
#include<cstring>
using namespace std;
int n, m, xx, yy;
char s1[12][12],s2[12][12];
int count_num()
{
int cnt = 0;
for(int i = 0;i < n;i++) {
for(int j = 0;j < n;j++) {
if(s1[i][j] == '*') cnt++;
}
}
return cnt;
}
int find_ld(int& x, int& y)
{
for(int i = 0;i < n;i++) {
for(int j = 0;j < n;j++) {
if(s1[j][i] == '*') {
x = i,y = j;
return 1;
}
}
}
return 0;
}
bool range(int i,int j) //避免RE
{
if(i >= 0 && i < m && j >= 0 && j < m)
return true;
return false;
}
int boom(int x, int y, int res)
{
int cnt = 0;
for(int i = 0;i < n;i++) { //在 yy 上面还有可能有可以消去的'*'
for(int j = 0;j < n;j++) {
if(range(yy + i - y, xx + j - x) && s2[yy + i - y][xx + j - x] == '*') { //大小图‘*’位置一一对应
if(s1[i][j] != '*') return false;
s1[i][j] = '.';
cnt++;
}
}
}
if(res != cnt) return 0;
return 1;
}
int main()
{
while(~scanf("%d%d",&n, &m) && n && m) {
if(!n && !m) break;
for(int i = 0;i < n;i++){
scanf("%s",s1[i]);
}
for(int i = 0;i < m;i++) {
scanf("%s",s2[i]);
}
int cnt = 0;
for(int i = 0;i < m;i++) {
for(int j = 0;j < m;j++) {
if(s2[j][i] == '*') {
if(!cnt) //小图中最左上角的位置
xx = i, yy = j;
cnt++; //小图中‘*’个数
}
}
}
int flag = (count_num() % cnt == 0)?1:0, x1 = -1, y1 = -1,c = 0;
while(flag) {
c++;
flag = find_ld(x1, y1); //寻找大图中最左上脚的位置
flag = boom(x1, y1, cnt); //消除大图中的‘*’
if(count_num() == 0) break; //大图没'*'了
if(c >= 2) flag = 0; //c为小图使用的次数
}
if(flag && c != 2) flag = 0; //必须用且只能用两个小图
printf("%d\n",flag?1:0);
}
return 0;
}