蓝桥杯 磁砖样式 【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;
}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值