标题:磁砖样式
小明家的一面装饰墙原来是 3*10 的小方格。
现在手头有一批刚好能盖住2个小方格的长方形瓷砖。
瓷砖只有两种颜色:黄色和橙色。
小明想知道,对于这么简陋的原料,可以贴出多少种不同的花样来。
小明有个小小的强迫症:忍受不了任何2*2的小格子是同一种颜色。
(瓷砖不能切割,不能重叠,也不能只铺一部分。另外,只考虑组合图案,请忽略瓷砖的拼缝)
显然,对于 2*3 个小格子来说,口算都可以知道:一共10种贴法,如【p1.png所示】
但对于 3*10 的格子呢?肯定是个不小的数目,请你利用计算机的威力算出该数字。
注意:你需要提交的是一个整数,不要填写任何多余的内容(比如:说明性文字)
思路:
看到是3*10的格子,可以考虑用dfs搜索一遍。每个格子有两种摆法,一种是横着放,一种是竖着放,两种颜色可以考虑用0,1表示,这样最后判断是否有重复的时候可以用位运算+Hash来判断。
摆放瓷砖一定要遵循一行拜访完再摆放下一行的规则,这样可以避免少考虑情况。
代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <map>
#include <time.h>
using namespace std;
const int maxn=1005;
int mp[maxn][maxn];
int row,col,ans;
map<int,int> Hash;
bool check()
{
for(int i=0;i<row;++i)
for(int j=0;j<col;++j)
{
if(i+1<row&&j+1<col)
if((mp[i][j]+mp[i+1][j]+mp[i][j+1]+mp[i+1][j+1])%4==0) return false;
}
return true;
}
void work(int x,int y)
{
if(mp[x][y]==-1)
{
///横放
if(y+1<col&&mp[x][y+1]==-1)
{
for(int i=0;i<2;++i)
{
mp[x][y]=mp[x][y+1]=i;
if(y+1<col) work(x,y+1);
else work(x+1,0);
mp[x][y]=mp[x][y+1]=-1;
}
}
///纵向
if(x+1<row&&mp[x+1][y]==-1)
{
for(int i=0;i<2;++i)
{
mp[x][y]=mp[x+1][y]=i;
if(y+1<col) work(x,y+1);
else work(x+1,0);
mp[x][y]=mp[x+1][y]=-1;
}
}
}
else
{
if(x==row-1&&y==col-1)
{
if(check())
{
int sum=0,bit=1;
for(int i=0;i<row;++i)
for(int j=0;j<col;++j)
{
sum+=bit*mp[i][j];
bit<<=1;
}
if(!Hash[sum])
{
ans++;
Hash[sum]++;
}
}
return;
}
if(y==col-1) work(x+1,0);
else work(x,y+1);
}
}
int main()
{
clock_t starttime,endtime;
while(scanf("%d%d",&row,&col)!=EOF)
{
//starttime=clock();
memset(mp,-1,sizeof(mp));
ans=0;
work(0,0);
//endtime=clock();
printf("%d\n",ans);
//printf("--%.5f\n",double(endtime-starttime)/CLOCKS_PER_SEC);
//time=4.20300s
}
return 0;
}