标题:磁砖样式
小明家的一面装饰墙原来是 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种。
如有不当之处欢迎指出!