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


    标题:磁砖样式

    小明家的一面装饰墙原来是 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种。


    如有不当之处欢迎指出!

  • 相关阅读:
    mybatis自动生成代码配置文件
    Struts2的类型转换器
    CSS布局自适应高度终极方法
    Winform WebBrowser控件对访问页面执行、改写、添加Javascript代码
    利用using语句解决Lock抛出异常时发生死锁的问题
    Flash与Silverlight终极大比拼
    System.Collections.Specialized.NameValueCollection PostVars
    Hook浏览器控件WebBrowser对WININET.dll的调用
    WebBrowser中打开新页面保留sessionid
    Linksys路由器自动重启加流量
  • 原文地址:https://www.cnblogs.com/flyawayl/p/8503152.html
Copyright © 2020-2023  润新知