题目描述

有一个高度是 h h,宽度是 ww 的二维表格,你要用 1×2 1\times2 和 2×1 2\times1 的地砖把表格铺满,有多少种不同的方案?
如下是一些样例:

输入格式 1777.in

输入包含多个测试用例。每个测试用例是由两个整数数字:高度 h h 和大型矩形的宽度 ww。输入由 h=w=0 h = w = 0 时终止。否则, 1≤h 1 \leq h, w≤11 w \leq 11。

输出格式 1777.out

每个测试数据输出一个答案。

输入样例 1777.in

1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0

输出样例 1777.out

1
0
1
2
3
5
144
51205


这题据说还有组合数学和其他各种(如插头dp)做法,不过既然作为状压 DP 的题目,我们还是考虑一下状压 DP 的做法。

首先,无论怎么铺,一定是要铺满的,这是重点。那么我们的状态中 0 和 1 就不可能表示“空”或“铺”了,而应该是考虑到另一个方面——铺法。
(也可以这么说:不是铺不铺的问题,而是怎么铺的问题。)

这题的基本铺法无非只有 1×2 1\times2 或 2×1 2\times1 两种,而要求的也就是不同的方案数。那么两种地砖 1×2 1\times2 或 2×1 2\times1,横的会影响左右(一行内相邻两列)、竖的会影响上下(一列内相邻两行)的取值。跟我们这几天做的其他一些 DP 类似,我们不妨设 f[i][set] f[i][set] 为铺满前 i i 行,其中第 ii 行的状态为 set set 的方案数。

关键是,我们要通过枚举两行的状态,消除限制。(这个要重点理解好)
状态转移时,有

f[i+1][k]←f[i+1][k]+f[i][j] for each possible new state k of j

f[i+1][k]\leftarrow f[i+1][k]+f[i][j]\text{ for each possible new state }\, k\text{ of }j

现在我们问题主要是如何判定方案的合法性,但先要解决状态所表示的含义。

我的处理方法是:在 f[i][set] f[i][set] 的 set set 中,0 表示某位“还有空间”(注意,不是不铺!),1 表示没有空间。那么在状态转移的时候,我是从当前行不断改进下一行的。现在就来集中精力考虑,比方说我们现在有一个 set set(例如101110),那么下一行肯定是?1???1。因为要满足铺满,所以右数第1位和第5位只能竖着放,剩下的 4 位有两种情况:暂时先不放,或横着放,这就是 set set 的合法状态。

那么我们其实就可以根据当前行已知状态,跑一遍 dfs,得到下一行的合法状态。反正数据范围小,怎么乱搞都无所谓啦。

解题细节:要开long long,多组数据 DP 数组记得清空。

最后还有,在跟同学交流的时候,有同学比较容易混乱。其实状压 DP 里面我们只要始终关注:0 和 1 的具体含义,状态的含义就可以了,不要混淆。

写初始化、状态转移和最终求答案的时候总是想一想:这里的状态是什么意思,应该怎么取值,再联系一下题目,应该怎么初始化、怎么转移、怎么求解,其实并不难。关键是要确定一种表示方法,0 和 1 的含义由始至终必须是唯一的,不然就会乱。

参考代码:

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>using namespace std;const int maxn = 15;int h, w;
long long dp[maxn][1 << maxn];int cnt;
int state[1 << maxn];void solve(int now, int k) { //dfs 求出所有可能的状态if (k + 1 == w) {state[cnt++] = now;return ;}solve(now, k + 1); //不放if (!(now & (1 << k)) && !(now & (1 << (k + 1)))) solve(now | (3 << k), k + 1); //无限制,横着放
}int main(void) {freopen("1777.in", "r", stdin);freopen("1777.out", "w", stdout);while (~scanf("%d%d", &h, &w)) {if (!h || !w) break;if (h * w & 1) { //特判puts("0");continue;}int upperLim = 1 << w;cnt = 0;solve(0, 0); //第一行的情况memset(dp, 0, sizeof dp);for (int i = 0; i < cnt; i++) dp[1][state[i]] = 1; //初始化for (int i = 1; i < h; i++)for (int j = 0; j < upperLim; j++) {cnt = 0;solve(upperLim - j - 1, 0);for (int k = 0; k < cnt; k++) dp[i + 1][state[k]] += dp[i][j];}printf("%lld\n", dp[h][upperLim - 1]);}return 0;
}

update:2017/4/13 讲评后

昨晚老师讲了另一种更简便的状态表示方法:0 表示没有限制地铺,不知道怎么铺,随便铺;1 表示这里已经有一个打竖铺的。
那么答案就是 f[n][0] f[n][0]。(无限制的所有方案数)

另外,在转移的时候,枚举第 i−1 i - 1行和第 i i 行状态,也就确定了它们对第 i+1i + 1 行的影响。设第 i−1 i - 1 行状态为 a a,第 ii 行状态为 b b,第 i+1i + 1 行为 c c,那么就有:c=(~b)&a,这是位运算的基本功。解释一下:

例如 aa 是 11001(三个竖铺,两个不确定), b b 可能是 11001(注意 aa 必须为 b b 的子集,因为在 aa 中竖铺的格子在 b b 中也要竖铺,那么 cc 的取值就是:先把 b b 取反,变成了 00110,再跟 aa 并,变成了 00000(没有限制)。这是因为竖铺的格子都在 i i 行和 i−1i - 1 行了,对 i+1 i + 1 行就不造成影响了。

对于看似复杂的问题,通过转化就可变为动态规划问题。而不同的规划方法也会影响编程实现的复杂度。因此,做题时,想清楚再开始打代码。

[SMOJ1777]铺地砖相关推荐

  1. 靠数学“拿了”两次诺贝尔奖,彭罗斯从“铺地砖”帮忙发现2011年化学奖的秘密...

    晓查 发自 凹非寺  量子位 报道 | 公众号 QbitAI 诺贝尔奖没有数学奖,但是如果数学足够好的话,可以拿两次诺贝尔奖: 帮别人拿一次,自己再拿一次. 刚刚获得诺贝尔奖的英国数学家罗杰·彭罗斯( ...

  2. ​迷“铺地砖”的数学家

    可以构成平面五重晶格铺砌的五种凸形砖 每当宗传明开始"闭关",谢绝一切会议.邀约时,熟悉他的人就能大致猜出,他又要"憋大招"了. 数学研究以抽象闻名,外行往往难 ...

  3. 青蛙过河 猴子爬山 兔子繁殖 开宝箱2 找气球 指针函数 铺地砖

    Problem A: 青蛙过河 Description 一条小溪尺寸不大,青蛙可以从左岸跳到右岸,在左岸有一石柱L,面积只容得下一只青蛙落脚,同样右岸也有一石柱R,面积也只容得下一只青蛙落脚.有一队青 ...

  4. [2022.1.13]UPC-2021级新生个人训练赛第22场-9783 Problem H 铺地砖

    问题 H: 铺地砖 时间限制: 1.000 Sec 内存限制: 128 M 题目描述 一天,晨晨的数学老师布置了一道题目,大意如下:用1×1和2×2的磁砖不重叠地铺满n×3的地板,共有多少种方案? 例 ...

  5. Problem C: 铺地砖——迭代小算法

    搜了一下百度,网上很多人都对这题没有深入下去进行解释,大多数只是通过枚举法就得出结论,因此我写了这篇博客讲讲我对这个题目的理解. 首先这道题目通过枚举法可以发现从第四项开始,方法总数就是前三项的和了, ...

  6. 铺地砖(找递推式 + 大数)

    铺地砖 时间限制: 1 Sec  内存限制: 128 MB 题目描述 一天,晨晨的数学老师布置了一道题目,大意如下:用1×1和2×2的磁砖不重叠地铺满n×3的地板,共有多少种方案? 例如:n=1时:1 ...

  7. Dynamo For Revit: 铺地砖

    前言 本文介绍如何用 Dynamo 铺地砖,仅仅是演示版,把基本思想梳理一下. 地砖效果 可以适用于不规则的地块,地砖长和宽可以调整. Dynamo 脚本逻辑 要完成这个功能: 找到要铺地砖的平面,设 ...

  8. 背地砖上楼的机器人_德国发明铺地砖机器人,效率大幅度上升,节省千万!

    小伙伴们应该都知道,再我们传统一点的建筑领域当中,给地面上铺砖可以说是一个十分考验技术的活了,不仅仅是需要我们拥有相当丰厚的经验还有技术,在工作的过程中我们还需要十分的细心,但是我们要是精益求精的话, ...

  9. 铺地砖问题 java

    问题描述  有一长度为N(1<=N<=10)的地板,给定两种不同瓷砖:一种长度为1,另一种长度为2,数目不限. 要将这个长度为N的地板铺满,一共有多少种不同的铺法? import java ...

最新文章

  1. SKU表管理之更新SKU表数据
  2. 随办 企业打造完美执行团队的终极利器
  3. 高性能javascript 文件加载阻塞
  4. python在线课程-《Python程序设计与应用》在线课程使用说明
  5. CSP认证201509-3 模板生成系统[C++题解]:字符串处理、模拟、哈希表、引号里面有空格的字符串怎么读入
  6. Java客户端操作zookeeper:删除节点代码示例
  7. Go语言 - 忍不了了!!!已将Go语言各标准包文档.移到自己服务器上
  8. 解读三种虚拟化之路连载一:x86虚拟化概述
  9. spring实现模板文件下载
  10. linux网站爬取,Kali下httrack 爬取网站页面
  11. Linux设置RSA密钥登录
  12. 提升研发效率 保障数据安全——阿里云宣布数据管理DMS企业版正式商业化
  13. php的curl如何返回值,怎么在PHP中利用CURL获取返回值
  14. HDU 4336 概率DP 状压
  15. (65)Verilog HDL多模块重复例化:generate for
  16. 关于数字签名简要原理
  17. vs2008的简单使用
  18. java 微博 屏蔽_最新JAVA调用新浪微博API之发微博(转)
  19. [转]XXX无法访问。你可能没有权限使用网络资源
  20. 从原理上搞懂编码——究竟什么是编码?什么是解码?什么是字节流?

热门文章

  1. Apache配置错误日志
  2. matlab调用opensees,基于OpenSees与MATLAB的逐步增量动力分析与数据处理方法技术
  3. java计算机毕业设计智慧机场管理系统源程序+mysql+系统+lw文档+远程调试
  4. zip分卷压缩linux命令,linux下zip分卷压缩及linux下zip分卷解压
  5. 虚拟机运行win11以及安装apk
  6. web html做菜单,Web元素设计之导航菜单
  7. BAT职级薪酬深度分析
  8. nginx中proxy_set_header Host $host的作用
  9. ADPCM编解码的使用
  10. Kotlin 异常处理