作者: Phill King

邮箱: phillking1982@163.com

原创文章,转载请注明出处。

题目地址:2411 -- Mondriaan's Dream

问题简单描述:

在一个N行M列的格子里,现有1*2大小的瓷砖,可以横着或者竖着铺。问一共有多少种方案,可以将整个N*M的空间都填满

示例:

N=2 ,M=4   一共5种方案

N = 2,M = 3; 一共3种方案

问题分析

1. 因为每块瓷砖的面积是2,所以总面积M*N必须是偶数才能铺满。如果是奇数,则方案数显然为0.

2. 分析一下覆盖的状态,用二进制来代表具体覆盖的方案:

用二进制来代表每一行的覆盖状态。 (0,1)代表竖着铺,(1,1)代表横着铺。

铺满的时候最后一排必然全部都是1.

状态转移:

此问题的状态转移比较复杂:

上一行的某个状态对应当前行的多个状态; 当前行的某个状态也可以来自上一行的多个状态。

状态转移示意图:

通过观察我们可以看到上一行到下一行状态转移的关系如下:

(注: 此处上一格代表上一行同一列位置的格子, 后一格代表同一行右侧的格子)

对于当前行的某一格来说:

  1. 如果上一格是0, 当前格必须是1.
  2. 如果上一格是1,
    1. 当前格可以是0,也可以是1,说明既可以竖着铺,也可以横着铺
    2. 如果当前格是横铺的第一个1,则后一格必须也是1,并且后一格的上一格不能为0

据此我们可以设计判断当前行能否从上一行状态转移过来的逻辑。

例子:

合法转移:

dp[i][10011] += dp[i-1][01100]

dp[i][10011] += dp[i-1][01111]

无法转移:

初始状态

第一行是没有上一行的,为了避免单独写第一行的逻辑。我们可以假设在第一行之上还存在初始行,我们把初始行的状态设为全1的时候方案为1,其他状态方案为0。 这样同样的逻辑我们可以转移到合法的第一行状态。

(注意:初始行只是提供初始状态,不需要考虑初始行本身全1是否合法。)

具体代码如下:

#include <iostream>
#include <algorithm>
#include <vector>using namespace std;bool validateLines(int upper, int lower, int width){for(int i=0; i<width;){if(((upper>>i)&1) == 0){    // upper line grid is 0 .if(((lower>>i)&1) == 0){return false;}i++;}else if(((lower>>i)&1) != 0){  // upper and current line grid is 1 .if(i == width-1 || ((lower>>(i+1))&1) == 0  || ((upper>>(i+1)&1)==0) ){return false;}else{i+=2;}}else{  // upper grid is 1, current grid is 0.i++;}}return true;
}long long int  getCoverWays(int rows, int cols){// the size of area must be even.if((rows*cols)%2 != 0){return 0;}// make sure columns is smaller;if(cols>rows){swap(rows,cols);}const int STATE_LIMIT = 1<<cols;vector<vector<long long int> > dp(2, vector<long long int>(STATE_LIMIT,0));int cur = 0;dp[cur][STATE_LIMIT-1] = 1;        // set the initial state before first linefor(int i=0; i<rows; i++){cur ^= 1;  // switch to current linestd::fill(dp[cur].begin(), dp[cur].end(), 0);   // clear the statesfor(int k=0; k<STATE_LIMIT; k++){if(dp[1-cur][k] != 0){for(int l=0; l<STATE_LIMIT; l++){if( ((k|l) == (STATE_LIMIT-1)) && validateLines(k,l, cols)){dp[cur][l] += dp[1-cur][k];}}}}}return dp[cur][STATE_LIMIT-1];
}int main() {int n = 4;int m = 11;cout<<getCoverWays(n, m)<<endl;return 0;
}

算法的时间复杂度为  , 因为M对时间的影响较大,如果M>N,可以交换二者,确保M的值较小。这样可以提高速度。

空间压缩:

因为只需要用到当前行和上一行的状态,所以只需要两个2^M的数组来保存状态即可。

总结:

这是一道经典的状态压缩动态规划问题。本文用整行作为状态来设计动态规划的算法,思路清晰,代码简洁。

本方法时间复杂度较高,还可以通过轮廓线动态规划的方法来进一步优化时间复杂度。

读者可以参考后续的文章 铺瓷砖问题(二)。

铺瓷砖问题 (状态压缩动态规划) (一)相关推荐

  1. 【动态规划】状态压缩动态规划

    整理的算法模板合集: ACM模板 目录 一.集合类状态压缩动态规划 A. AcWing 91. 最短Hamilton路径 B.AcWing 524. 愤怒的小鸟 二.连通类(棋盘类)状态压缩动态规划 ...

  2. 【转】状态压缩动态规划

    引入  首先来说说"状态压缩动态规划"这个名称,顾名思义,状态压缩动态规划这个算法包括两个特点,第一是"状态压缩",第二是"动态规划". 状 ...

  3. 状态压缩动态规划 - 总结【普及+,提高-】

    状态压缩动态规划是一类特殊的动态规划,通常有一维用来表示一个二进制状态.状态压缩,顾名思义,就是把原来要一个bool数组表示状态压缩到一个int变量里.围绕状压DP,我们将介绍它的前世今生,领略状压D ...

  4. 【SGU 448】Controlled Tournament(状态压缩动态规划)

    题目链接 [SGU 448]Controlled Tournament 题目大意 给定比赛人员个数nnn,你希望赢的人的编号m" role="presentation" ...

  5. 状态压缩动态规划部分习题详解

    状态压缩动态规划部分习题详解 状压DP部分题目详解 状态压缩动态规划部分习题详解 简介 经典子集类问题 原子弹 最短路与状压DP结合 送礼物 P3959宝藏 旅游 经典网格类 铺地砖 一笔画 其他类型 ...

  6. 状态压缩动态规划 -- 旅行商问题

    旅行商问题: N个点(N<16)的带权有向图D,求一条路径,使得这条路经过每一个点恰好一次. 而且路径上边的权值和最小(或者最大),或者求一条具有这样性质的回路. 状态压缩: 将二进制表示十进制 ...

  7. UOJ 265 NOIP 2016 DAY2 T3 浅谈预处理状态压缩动态规划

    世界真的很大 要是当年我会一点状压该多好.. 虽然现在我状压也很差,但是还是把这道题水出来了 马上要NOIP2017了,抓紧调整状态才好 看题先: description Kiana 最近沉迷于一款神 ...

  8. [NOI2015]寿司晚宴(状态压缩动态规划)

    题目描述 为了庆祝NOI的成功开幕,主办方为大家准备了一场寿司晚宴.小G和小W作为参加NOI的选手,也被邀请参加了寿司晚宴. 在晚宴上,主办方为大家提供了n−1种不同的寿司,编号1,2,3,⋯,n-1 ...

  9. 0x56. 动态规划 - 状态压缩DP(习题详解 × 7)

    目录 Problem A. 最短Hamilton路径 ProblemB. 蒙德里安的梦想 Problem C. Corn Fields Problem D. 小国王 Problem E. 炮兵阵地 P ...

最新文章

  1. 树莓派 Zero 与 Zero W 对比
  2. JDK之jstat的用法
  3. numpy.random.randn()与numpy.random.rand()的区别(转)
  4. PS教程第一课:PS简介
  5. java 方法 示例_Java扫描仪的hasNextBoolean()方法与示例
  6. 输入快捷键显示未知命令_「干货」华为VRP基础和常用命令了解一下
  7. UI设计|搭配色彩素材专辑,轻松掌握要点
  8. 背景图片的位置(HTML、CSS)
  9. 探索Spring异步代理循环依赖失败的问题
  10. 电脑面上,在电脑桌面上添加文字_在电脑桌面上添加图片
  11. html文件如何做成链接,如何将文件做成超链接HTM网页?
  12. 绝了!超全面的Java调优方案,我司已用7年,并得到验证!(万能通用)
  13. idea启动后项目启动报错,必须得记录一下
  14. 基于matlab测量物体直径,基于MATLAB的零件尺寸检测误差分析的软件设计
  15. 道路交通标志设计要素和基本原则
  16. Q_INVOKABLE与invokeMethod用法详解
  17. 云之讯刘泽阳:互联网线上流量越来越贵,倒逼营销归于传统渠道|企服三会系列报道...
  18. Http请求之GET,POST,PUT,DELETE方法详解
  19. html5简单企业网站,HTML5企业网站极简大气模板
  20. js判断 pc 手机 浏览器

热门文章

  1. 高等数学学习笔记——第七十一讲——多元函数的泰勒公式
  2. MATLAB numel()函数
  3. 【HAVENT原创】JS 屏蔽/禁止双击选中文字
  4. 【MindSpore易点通机器人-05】问答数据预处理及编码
  5. php错误403_phpstudy 报403错误怎么办
  6. 研究生应该具备的学术素养
  7. 代码随想录算法训练营day42 | 01背包问题,你该了解这些!,01背包问题,你该了解这些! 滚动数组 , 416. 分割等和子集
  8. 太原理工大学2021数据结构课程设计(交通咨询系统(最短路径问题))
  9. 北京计算机专业基础,北京工业大学2020年考研895计算机学科专业基础参考书目...
  10. jsoup解析html元素,辅助实现元素定位