藍橋杯 磁磚樣式 【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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章