标题:磁砖样式
小明家的一面装饰墙原来是 3*10 的小方格。
现在手头有一批刚好能盖住2个小方格的长方形瓷砖。
瓷砖只有两种颜色:黄色和橙色。
小明想知道,对于这么简陋的原料,可以贴出多少种不同的花样来。
小明有个小小的强迫症:忍受不了任何22的小格子是同一种颜色。
(瓷砖不能切割,不能重叠,也不能只铺一部分。另外,只考虑组合图案,请忽略瓷砖的拼缝)
显然,对于 23 个小格子来说,口算都可以知道:一共10种贴法,如【p1.png所示】
但对于 3*10 的格子呢?肯定是个不小的数目,请你利用计算机的威力算出该数字。
注意:你需要提交的是一个整数,不要填写任何多余的内容(比如:说明性文字)
用wall[][]数组表示状态(-1表示没贴,0表示贴了黄色,1表示贴了红色)
用dfs解决,但是注意搜索分类
1.(x,y)处空着
横着贴(贴完判是不是还可以继续一行贴) 竖着贴(贴完判是不是还可以继续一行贴)
2.(x,y)处有砖
横着下一个位置继续贴 下一行开头开始贴
因为要忽略瓷砖拼缝所以一定要去重,同一个图案会有几种不同的贴法实现(set进行去重,用字符串代表一次方案的贴法)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<set>
using namespace std;
int wall[10000][10000];//墙
int n,m;
set<string> se;
//判断树是否满足条件
bool check(){
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
if((wall[i][j]+wall[i][j+1]+wall[i+1][j]+wall[i+1][j+1])%4==0){//保证正方形不同色
return false;
}
}
}
return true;
}
void dfs(int x,int y){
if(x==n+1){//贴完了
if(check()){
string s = "";
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s+=wall[i][j];
}
}
se.insert(s);
}
return;
}
if(wall[x][y]==-1){//这个地方空着
if(wall[x][y+1]==-1&&y+1<=m){//可以横着贴
for(int color=0;color<2;color++){//选一种颜色
wall[x][y]=wall[x][y+1]=color;
if(y+2<=m)dfs(x,y+2);//贴完之后还可以继续往后贴
else dfs(x+1,1);//贴完之后要到下一排开始贴
wall[x][y]=wall[x][y+1]=-1;
}
}
if(wall[x+1][y]==-1&&x+1<=n){//可以竖着贴
for(int color=0;color<2;color++){//选一种颜色
wall[x][y]=wall[x+1][y]=color;
if(y+1<=m)dfs(x,y+1);//贴完之后还可以继续往后贴
else dfs(x+1,1);//贴完之后要到下一排开始贴
wall[x][y]=wall[x+1][y]=-1;
}
}
}else{//有砖
if(y==m)dfs(x+1,1);
else dfs(x,y+1);
}
}
int main(){
memset(wall,-1,sizeof(wall));
cin>>n>>m;
dfs(1,1);
cout<<se.size()<<endl;
return 0;
}