第八届蓝桥杯决赛 磁砖样式

标题:磁砖样式

小明家的一面装饰墙原来是 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
", ans);
81     return 0;
82 }

只需要1s就算出来答案了,合理的铺放方式共有101466种。


如有不当之处欢迎指出!

原文地址:https://www.cnblogs.com/flyawayl/p/8503152.html