蓝桥杯 磁砖样式 【dfs + 去重】
标题:磁砖样式
system.out 为啥是“磁”砖?????? 蓝桥水到这样了么??????
小明家的一面装饰墙原来是 3*10 的小方格。
现在手头有一批刚好能盖住2个小方格的长方形瓷砖。
瓷砖只有两种颜色:黄色和橙色。小明想知道,对于这么简陋的原料,可以贴出多少种不同的花样来。
(瓷砖不能切割,不能重叠,也不能只铺一部分。另外,只考虑组合图案,请忽略瓷砖的拼缝)
显然,对于 2*3 个小格子来说,口算都可以知道:一共10种贴法,如【p1.png所示】
但对于 3*10 的格子呢?肯定是个不小的数目,请你利用计算机的威力算出该数字。
注意:你需要提交的是一个整数,不要填写任何多余的内容(比如:说明性文字)
小明有个小小的强迫症:忍受不了任何2*2的小格子是同一种颜色。
答案: 101466
解题思路
这题是道填空题,而且数据也不是特别多,所以不用关心时间的问题,肯定能在几秒内出结果。(若果写对了)
这个题看到第一眼就可以看出来是dfs搜索+去重,这题dfs的问题在:如何判断已经铺满瓷砖了。
解决办法:我们在铺瓷砖的时候,假如装饰墙有n*m个方格,我们现在位于( x, y) ,无论我们此时横着铺还是竖着铺( 如果(x , y) 还能铺),或者不铺,如果我们下一步能走到(x,y+1)就一定要走到(x,y+1),如果不能就去(x+1,1)。即我们在铺第x+1行的时候保证前x行已经铺满了。当我们走到n+1行的时候,装饰墙也就铺满了。
位运算+map 判重(话说这叫hash???) 当然也可用set< set<int > > s,最后结果就是s.size()。
AC代码
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
int mp[4][11],n=3,m=10,tot;
map <int,int> check;
bool Judge()
{
for(int i=1;i<=n-1;i++) {
for(int j=1;j<=m-1;j++) {
if((mp[i][j]+mp[i][j+1]+mp[i+1][j]+mp[i+1][j+1])%4 == 0)
return false;
}
}
return true;
}
void dfs(int x,int y)
{
if(x == n+1) {
if(Judge()) {
int bit=1,sum=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
sum += bit*mp[i][j];
bit = bit << 1;
}
}
if(!check[sum]) {
tot++;
check[sum]++;
}
}
return;
}
if(mp[x][y] == -1) {
if(y < m && mp[x][y+1] == -1) { //横着
for(int i=0;i<2;i++) {
mp[x][y] = i;
mp[x][y+1] = i;
if(y+2 <= m)
dfs(x,y+2);
else
dfs(x+1,1);
mp[x][y] = -1;
mp[x][y+1] = -1;
}
}
if(x < n && mp[x+1][y] == -1) { //竖着
for(int i=0;i<2;i++) {
mp[x][y] = i;
mp[x+1][y] = i;
if(y+1 <= m)
dfs(x,y+1);
else
dfs(x+1,1);
mp[x][y] = -1;
mp[x+1][y] = -1;
}
}
}
else {
if(y < m)
dfs(x,y+1);
else
dfs(x+1,1);
}
}
int main()
{
memset(mp,-1,sizeof mp);
tot = 0;
dfs(1,1);
cout << tot << endl;
}