Description
Solution
直接暴力。
用结构体记录好每片拼图的构成,然后对于每片拼图,遍历左上角放的位置,判断能否放置,如果能放就放。最后判断这个正方形是否被填满。
一点点小的优化:因为当结果超过 1 时,不要求总方案数,因此当我们得到两种方案后,就可以直接结束递归了。
当然这题也是可以用状压的。
Code
#include<cstdio>
#define N 20
using namespace std;
struct node
{
int r,c,p[5][5];
}a[N];
int n,ansnum,ans[5][5],d[5][5];
bool flag;
char s[5];
bool ful()
{
for (int i=1;i<=4;++i)
for (int j=1;j<=4;++j)
if (!d[i][j]) return false;
return true;
}
bool check(int x,int y,int id)
{
for (int i=1;i<=a[id].r;++i)
for (int j=1;j<=a[id].c;++j)
{
if (!a[id].p[i][j]) continue;
if (x+i-1>4) return false;
if (y+j-1>4) return false;
if (d[x+i-1][y+j-1]) return false;
}
return true;
}
void setin(int x,int y,int id,int num)
{
for (int i=1;i<=a[id].r;++i)
for (int j=1;j<=a[id].c;++j)
{
if (!a[id].p[i][j]) continue;
d[x+i-1][y+j-1]=num;
}
}
void dfs(int x)
{
if (flag) return;
bool k=ful();
if (k||x>n)
{
if (k)
{
if (ansnum)
{
++ansnum;
flag=true;
}
else
{
ansnum=1;
for (int i=1;i<=4;++i)
for (int j=1;j<=4;++j)
ans[i][j]=d[i][j];
}
}
return;
}
for (int i=1;i<=4;++i)
for (int j=1;j<=4;++j)
{
if (check(i,j,x))
{
setin(i,j,x,x);
dfs(x+1);
setin(i,j,x,0);
}
}
dfs(x+1);
}
int main()
{
freopen("puzzle.in","r",stdin);
freopen("puzzle.out","w",stdout);
while (scanf("%d",&n)!=EOF)
{
for (int i=1;i<=n;++i)
{
scanf("%d%d",&a[i].r,&a[i].c);
for (int j=1;j<=a[i].r;++j)
{
scanf("%s",s+1);
for (int k=1;k<=a[i].c;++k)
a[i].p[j][k]=s[k]-'0';
}
}
ansnum=0;
flag=false;
for (int i=1;i<=4;++i)
for (int j=1;j<=4;++j)
ans[i][j]=d[i][j]=0;
dfs(1);
if (ansnum==0) printf("No solution\n");
else if (ansnum>=2) printf("Yes, many!\n");
else
{
printf("Yes, only one!\n");
for (int i=1;i<=4;++i)
{
for (int j=1;j<=4;++j)
printf("%d",ans[i][j]);
printf("\n");
}
}
}
return 0;
}