Mondriaan's Dream

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 17203   Accepted: 9918

Description

Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series' (where he had to use his toilet paper to draw on, for all of his paper was filled with squares and rectangles), he dreamt of filling a large rectangle with small rectangles of width 2 and height 1 in varying ways. 

Expert as he was in this material, he saw at a glance that he'll need a computer to calculate the number of ways to fill the large rectangle whose dimensions were integer values, as well. Help him, so that his dream won't turn into a nightmare!

Input

The input contains several test cases. Each test case is made up of two integer numbers: the height h and the width w of the large rectangle. Input is terminated by h=w=0. Otherwise, 1<=h,w<=11.

Output

For each test case, output the number of different ways the given rectangle can be filled with small rectangles of size 2 times 1. Assume the given large rectangle is oriented, i.e. count symmetrical tilings multiple times.

Sample Input

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

Sample Output

1
0
1
2
3
5
144
51205

题意:

用 1 x 2 的矩形骨牌覆盖 h x w 的矩形,问有多少种不同的覆盖方法。

思路:

轮廓线dp(状压dp),以一个 w(矩形的宽) 位的二进制数(设为 k)表示一个状态,对应位上的 0 表示未覆盖的状态、1 表示已覆盖。

我们以从左到右、从上倒下的顺序做决策,要决策的点是 k 所表示的状态的下一个位置,以此点作为骨牌的右下角,

即:若我们在当前点竖着放置一块骨牌,它将覆盖当前点和正上方一点;若我们横着放置一块骨牌,它将覆盖当前点和左边的点。只有这样决策,才保证了是从之前的状态转移过来。

且以上述方式记录状态,k 的最高位正好是决策点的正上方一点,最低位是决策点的左边一点,并且我们每次决策都要保证最高位为 1 ,否则在以后的决策中都无法为其覆盖骨牌,也就无法达到全覆盖的要求。

这样,对于每个点都有三种决策方式:

  1. 放一块竖着的骨牌,要满足的条件有:k 的最高位不为 1 ;当前点不在第一行。则转移后的状态是 curk = k<<1|1,左移一位并将最低位覆盖;
  2. 放一块横着的骨牌,要满足的条件有:k 的最高位是1、最低位不试 1;当前点不在第一列。转移后的状态是 curk=(k|1)<<1|1,在覆盖最低位,左移一位后再覆盖最低位;
  3. 不妨骨牌,要满足的条件有: k 的最高位是 1;状态 curk = k<<1;

注:每次状态转移后都要清除高于 w 位的多余位,这些并不是状态的一部分;左移得到下一状态应该好理解。

代码:

#include<iostream>
#include<bitset>
#include<cstring>
using namespace std;
const long long maxn = 12, INF = 0x3f3f3f3f; long long dp[2][1<<maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0); long long h, w;
while(cin>>h>>w && (h+w))
{
memset(dp, 0, sizeof(dp));
long long cur=0, curk;
dp[cur][(1<<w)-1]=1;
for(int i=0; i<h; ++i)
{
for(int j=0; j<w; ++j)
{
cur=1-cur;
memset(dp[cur], 0, sizeof(dp[cur]));
for(int k=0; k<(1<<w); ++k)
{
if(i>0 && !(k&(1<<(w-1))))//放一块竖着的骨牌,覆盖当前位置和正上方的位置
{
curk=k<<1|1;
curk=curk&((1<<w)-1);//清除多余的位
dp[cur][curk]+=dp[1-cur][k];
}
if(j>0 && !(k&1) && (k&(1<<(w-1))))//放一块横着的骨牌,覆盖当前位置和左边的位置
{
curk=(k|1)<<1|1;
curk=curk&((1<<w)-1);
dp[cur][curk]+=dp[1-cur][k];
}
if((k&(1<<(w-1))))//不放
{
curk=k<<1;
curk=curk&((1<<w)-1);
dp[cur][curk]+=dp[1-cur][k];
}
}
}
}
cout<<dp[cur][(1<<w)-1]<<endl;
}
return 0;
}

poj2411 Mondriaan's Dream (轮廓线dp、状压dp)的更多相关文章

  1. 【BZOJ】1076 [SCOI2008]奖励关 期望DP+状压DP

    [题意]n种宝物,k关游戏,每关游戏给出一种宝物,可捡可不捡.每种宝物有一个价值(有负数).每个宝物有前提宝物列表,必须在前面的关卡取得列表宝物才能捡起这个宝物,求期望收益.k<=100,n&l ...

  2. CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

    问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高 ...

  3. hdu 4352 "XHXJ's LIS"(数位DP+状压DP+LIS)

    传送门 参考博文: [1]:http://www.voidcn.com/article/p-ehojgauy-ot.html 题解: 将数字num字符串化: 求[L,R]区间最长上升子序列长度为 K ...

  4. [转]状态压缩dp(状压dp)

    状态压缩动态规划(简称状压dp)是另一类非常典型的动态规划,通常使用在NP问题的小规模求解中,虽然是指数级别的复杂度,但速度比搜索快,其思想非常值得借鉴. 为了更好的理解状压dp,首先介绍位运算相关的 ...

  5. 状态压缩dp 状压dp 详解

    说到状压dp,一般和二进制少不了关系(还常和博弈论结合起来考,这个坑我挖了还没填qwq),二进制是个好东西啊,所以二进制的各种运算是前置知识,不了解的话走下面链接进百度百科 https://baike ...

  6. 洛谷 P3343 - [ZJOI2015]地震后的幻想乡(朴素状压 DP/状压 DP+微积分)

    题面传送门 鸽子 tzc 竟然来补题解了,奇迹奇迹( 神仙题 %%%%%%%%%%%% 解法 1: 首先一件很明显的事情是这个最小值可以通过类似 Kruskal 求最小生成树的方法求得.我们将所有边按 ...

  7. POJ2411 Mondriaan's Dream 轮廓线dp

    第一道轮廓线dp,因为不会轮廓线dp我们在南京区域赛的时候没有拿到银,可见知识点的欠缺是我薄弱的环节. 题目就是要你用1*2的多米诺骨排填充一个大小n*m(n,m<=11)的棋盘,问填满它有多少 ...

  8. 51nod 1673 树有几多愁(链表维护树形DP+状压DP)

    题意 lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输出 ...

  9. BZOJ3836 [Poi2014]Tourism 【树形dp +状压dp】

    题目链接 BZOJ3836 题解 显然这是个\(NP\)完全问题,此题的解决全仗任意两点间不存在节点数超过10的简单路径的性质 这意味着什么呢? \(dfs\)树深度不超过\(10\) \(10\)很 ...

  10. bzoj1076: [SCOI2008]奖励关(期望dp+状压dp)

    1076: [SCOI2008]奖励关 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2989  Solved: 1557[Submit][Statu ...

随机推荐

  1. zabbix邮件报警设置(加密)

    邮件设置如下 端口号选择465

  2. hystrix动态修改参数

    Hystrix 从入门到深入——运行时修改动态配置 /** * * @author zhangshuo * */ @Component public class DynamicConfigSource ...

  3. tomact在windows系统下安装

    一.下载 下载地址: https://tomcat.apache.org/download-90.cgi 7,8,9的版本都可以下,这里下载最新版本 注意:Binary是编译好的,可以直接使用的版本, ...

  4. Redis5设计与源码分析读后感(二)简单动态字符串SDS

    一.引言 学习之前先了解几个概念: SDS定义:简单动态字符串,Redis的基本数据结构之一,用于储存字符串和整型数据. 二进制安全:C语言中用"\0"表示字符串结束,如果字符串本 ...

  5. spring的AspectJ基于XML和注解(前置、后置、环绕、抛出异常、最终通知)

    1.概念 (1)AspectJ是一个基于Java语言的AOP框架 (2)Spring2.0以后新增了对AspectJ切入点表达式的支持 (3)AspectJ是AspectJ1.5的新增功能,通过JDK ...

  6. Java泛型中的类型参数和通配符类型

    类型参数 泛型有三种实现方式,分别是泛型接口.泛型类.泛型方法,下面通过泛型方法来介绍什么是类型参数. 泛型方法声明方式:访问修饰符 <T,K,S...> 返回类型 方法名(方法参数){方 ...

  7. Python-函数式编程-map reduce filter lambda 三元表达式 闭包

    lambda 匿名函数,核心是作为算子,处理逻辑只有一行但具有函数的特性,核心用于函数式编程中 三元运算符 其实本质上是if分支的简化版,满足条件返回 if 前面的值,不满足条件返回 else后面的值 ...

  8. Python-判断变量类型和继承链-type isinstance

    在很多情况下,需要对类型进程动态判断,因为不同的数据类型不能互相做运算并且各自拥有不同的运算逻辑,所有需要判断对象的类型,常用的是type和isinstance,type更过用于获取对象是什么类型构建 ...

  9. CTFweb方向小知识点

    1)转义字符 \x35\x35\x2c\x35\x36\x2c\x35\x34\x2c\x37\x39 这玩意叫转义字符,在C.C++里直接用cout << "\x35\x2c\ ...

  10. Java知识系统回顾整理01基础04操作符07Scanner

    一.Scanner 需要用到从控制台输入数据时,使用Scanner类. 二.使用Scanner读取整数 注意: 使用Scanner类,需要在最前面加上 import java.util.Scanner ...