1. 程式人生 > >第八屆藍橋杯決賽 磁磚樣式

第八屆藍橋杯決賽 磁磚樣式

map 思路 藍橋杯 jsb 標題 分享 。。 amp span

標題:磁磚樣式

小明家的一面裝飾墻原來是 3*10 的小方格。
現在手頭有一批剛好能蓋住2個小方格的長方形瓷磚。
瓷磚只有兩種顏色:黃色和橙色。
小明想知道,對於這麽簡陋的原料,可以貼出多少種不同的花樣來。
小明有個小小的強迫癥:忍受不了任何2*2的小格子是同一種顏色。
(瓷磚不能切割,不能重疊,也不能只鋪一部分。另外,只考慮組合圖案,請忽略瓷磚的拼縫)
顯然,對於 2*3 個小格子來說,口算都可以知道:一共10種貼法,如【p1.png所示】
但對於 3*10 的格子呢?肯定是個不小的數目,請你利用計算機的威力算出該數字。

註意:你需要提交的是一個整數,不要填寫任何多余的內容(比如:說明性文字)

技術分享圖片


思路

  去年比賽時被這題坑了,一直想用輪廓線動態規劃去做。。。其實直接暴力搜索就可以。

  依次枚舉每一個格子,每擺放滿一行,再嘗試去擺放下一行。在位置$(x,y)$處有兩種擺放方式:橫向和縱向。

  當擺滿所有格子的時候就檢查是否出現某個2*2的小格子是同一種顏色,以及這種擺放方式是否已經計算過。我是采用二進制來表示每一種能鋪滿的情況,黃色用0表示,橙色用1表示,再用map來記錄和判斷是否重復計算。


詳細代碼

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <map>
 4 #include <algorithm>
 5 using namespace std;
6 const int w = 3, h = 10; 7 int graph[w][h]; 8 int ans = 0; 9 10 map<int, int> Hash; 11 12 //檢查2x2格子顏色是否相同 13 bool check_color() { 14 for(int i = 0; i < w; i++) 15 for(int j = 0; j < h; j++) { 16 if(i+1 < w && j+1 < h) { 17 if((graph[i][j]+graph[i][j+1
]+graph[i+1][j]+graph[i+1][j+1]) % 4 == 0) 18 return false; 19 } 20 } 21 return true; 22 } 23 24 void fill_with_tile(int x, int y) { 25 if(graph[x][y] == -1) { 26 //橫向擺放 27 if(y+1 < h && graph[x][y+1] == -1) { 28 29 for(int i = 0; i < 2; i++) { 30 graph[x][y] = graph[x][y+1] = i; 31 if(y == h-1) { //鋪下一行 32 fill_with_tile(x+1, 0); 33 } else { //鋪當前行的下一個格子 34 fill_with_tile(x, y+1); 35 } 36 graph[x][y] = graph[x][y+1] = -1; 37 } 38 39 } 40 //縱向擺放 41 if(x+1 < w && graph[x+1][y] == -1) { 42 for(int i = 0; i < 2; i++) { 43 graph[x][y] = graph[x+1][y] = i; 44 if(y == h-1) { //鋪下一行 45 fill_with_tile(x+1, 0); 46 } else { //鋪當前行的下一個格子 47 fill_with_tile(x, y+1); 48 } 49 graph[x][y] = graph[x+1][y] = -1; 50 } 51 } 52 } else { 53 if(x == w-1 && y == h-1) { //成功鋪滿 54 if(check_color()) { 55 //判斷是否出現重復情況 56 int ret = 0, bit = 1; 57 for(int i = 0; i < w; i++) 58 for(int j = 0; j < h; j++) { 59 ret += graph[i][j] * bit; 60 bit *= 2; 61 } 62 if(!Hash.count(ret)) { 63 Hash[ret] = 1; 64 ans++; 65 } 66 } 67 return; 68 } 69 if(y == h-1) { //鋪下一行 70 fill_with_tile(x+1, 0); 71 } else { //鋪當前行的下一個格子 72 fill_with_tile(x, y+1); 73 } 74 } 75 } 76 77 int main() { 78 memset(graph, -1, sizeof(graph)); 79 fill_with_tile(0, 0); 80 printf("%d\n", ans); 81 return 0; 82 }

只需要1s就算出來答案了,合理的鋪放方式共有101466種。


如有不當之處歡迎指出!

第八屆藍橋杯決賽 磁磚樣式