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 Specification

The input file 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 Specification

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

Input

Specification

The input file 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

Specification

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

今天集训做这题用怎样的dp都会跪,然后我就自己模拟,还是跪......最后前辈SD指导,原来这是典型的状态压缩问题(所谓状态压缩也弄不懂啥专业术语,就知道针对这题采用的是二进制策略将d[2][][][][][]...后面的m维数组映射为一个2进制的m位,从而用一个d[2][1<<m]的二维数组就搞定啦),下面是对这题我的理解....我是从一点不懂,然后从多段图路径看到轮廓线动态压缩,然后又根据图研究本题的构造方法,最后又理解2进制操作,感觉做ACM的题目好充实,哈哈,加油!!!

 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,cur; const int maxn=;
long long d[][<<maxn]; int main(){
while(scanf("%d%d",&n,&m)==){
if(m== && n==)return ;
if(n<m)swap(n,m);
memset(d,,sizeof(d));
cur=;
d[][(<<m)-]=;//所有d[0][j]初始化为1
for(int i=;i<n;i++)
for(int j=;j<m;j++){//从小到大枚举每一个阶段(共m*n阶段)
cur^=;
memset(d[cur],,sizeof(d[cur]));
for(int k=;k<(<<m);k++){//枚举上个阶段的状态(0-2*m-1)
if(k&(<<m-))d[cur][(k<<)^(<<m)]+=d[-cur][k];//不放
if(i && !(k&(<<m-)))d[cur][(k<<)^]+=d[-cur][k];//插上
if(j && (k&(<<m-)) && !(k&))d[cur][(k<<)^(<<m)|(<<)^]+=d[-cur][k];//插左
}
}
printf("%lld\n",d[cur][(<<m)-]);
}
return ;
}
/*《明明很爱你——品冠、梁静茹,伤感唯美》《红日——杨克勤,热血,积极》《如果你也听说——张惠妹,爱情,伤感》
^_^!状态压缩——轮廓线动态规划
^_^!共同特点:在一个比较"窄"(行数少或者列数少)的棋盘上进行复杂操作。如过采用传统方法(以整行或者整列为状态)进行规划,
将无法进行状态转移,因此只能把参差不齐的轮廓线也作为状态转移的一部分。
^_^!方法:要用到递推关系里的多段图路径问题:从左到右有n列节点,每列称为"一个阶段",每个阶段的结点只能向下一阶段连有向
边(每个结点出发可以连多条边),求从阶段1到阶段n每个结点的路径条数(起点可以任意,只要是从阶段1开始的即可)
>> 设d[i][j]为从阶段1到结点(i,j)的路径条数,则伪代码为(已用滚动数组)
>> cur=0;
>> 所有d[0][j]初始化为1
>> 从小到大枚举每个要算的阶段{ //采用动态数组思想实现上下2层数据更新
>> cur^=1;//d[2][m]--->一层为d[cur][...]另一层为d[1-cur][...]两层数据轮换为cur^=1;
>> 所有d[cur][j]初始化为0//只能放在这,因为在d[cur]存着以前某个阶段的值
>> for 上个阶段每个结点j
>> for j的每个后继结点k
>> d[cur][k]+=d[1-cur][j]
>> }
>> 这里cur就是"正在计算"的那一阶段。最后d[cur]为阶段n各结点的值。不难发现,这些节点的名字和编号并不重
>> 要,只需要从小到大枚举这些阶段就好
^_^!本题:铺放骨牌(用1x2的骨牌覆盖nxm的棋盘,有多少种方法?输入韩多组数据,每组包含2个整数m,n(m*n<=100),当m==n==0时
结束),对于每组数据输出总数。
^_^!解题思路:1>因为题目中n*m<=100所以m、n至少有一个不超过10。为简单起见,我们规定m=<n,如果n>m就交换,来符合前面说的
"窄"棋盘条件;
2>这里按照从上到下、从左到右的顺序把棋盘分成m*n个阶段,每个阶段包含m个棋盘区域(第n行m列的1x1的方块及其后
的m-1个),我们用1已覆盖,0表示未被覆盖,这样每个阶段所有情况就是所有m位二进制,共2的m次方个结点;
3>阶段决策是:"以当前格子为右下角,要不要放骨牌以及放哪种骨牌"。答案有3种:不放骨牌、放竖骨牌、放横骨牌
$(i,j)在右下角竖放即插入上一层,横放是占据前一个和(i,j)位置$ 【】【】【】【】【】
【】【】【】【】【】
【】【】[k4][k3][k2]
[k1][k0](i,j)
|
|
|----------- 【】【】【】【】【】
| 【】【】【】【】【】
| 【】【】 1 [k3][k2]
| [k1][k0][0] //不放的情况只有当k4==1时,转移到k3k2k1k00状态
|
|----------- 【】【】【】【】【】
| 【】【】【】【】【】
| 【】【】 1 [k3][k2]
| [k1][k0][1] //往上放的情况只有当k4==0 && i!=最上层时,转移到k3k2k1k01
|
|----------- 【】【】【】【】【】
| 【】【】【】【】【】
| 【】【】 1 [k3][k2]
| [k1][1] [1] //往左放的情况只有当k4==1 && k0==0 && j不是最左层时,转移到k3k2k111
|
^_^!算法复杂度为O(mn*2^m),最终答案为d[cur][2^m-1] (因为是从0开始编号的最后一个阶段即m*n-1,又因为该算法采用滚动
数组法,所以最后一个阶段数值保存在d[cur][...]里,上面说的设d[i][j]为从阶段1到结点(i,j)的路径条数,这里我们为了
防止开一个d[2][k4][k3][k2][k1][k0]的数组,所以将后面m维映射为一个2进制整数2^k4+2^k3+2^k2+2^k1+2^k0共
是0-2^m-1个结点,所以最后一个阶段最后一个结点存的就是答案)
^_^!位运算实现状态转移:设旧状态为k,则:
A:不放,条件:二进制k从左往右第一个为1,即:k & (1<<m-1));
新状态为k左移一位的结果:k<<1;
B:上插,条件:二进制k从左往右第一个为0 && i不为顶,即:i && !(k&(1<<m-1))
新状态为k左移一位最后一位变为1:(k<<1)^1
C:左插,条件:二进制k最左一位为1,最右一位为0,且j不为左,即:j && (k&(1<<m-1)) && !(k&1)
新状态为k左移一位最后一位和倒数第二位变为1
*/

[ACM_动态规划] 轮廓线动态规划——铺放骨牌(状态压缩1)的更多相关文章

  1. 动态规划——用二进制表示集合的状态压缩DP

    动态规划当中有非常常见的一个分支--状态压缩动态规划,很多人对于状态压缩畏惧如虎,但其实并没有那么难,希望这文章能带你们学到这个经典的应用. 二进制表示状态 在讲解多重背包问题的时候,我们曾经讲过二进 ...

  2. UVa 11270 铺放骨牌(轮廓线DP)

    https://vjudge.net/problem/UVA-11270 题意: 用1×2骨牌覆盖n×m棋牌,有多少种方法? 思路: 这道题目是典型的轮廓线DP题. 所谓轮廓线DP,就是以整行整列为状 ...

  3. 铺放骨牌 uva11270

    题解: 插头dp裸题 没什么好说的啊就是n个二进制位表示状态 相比原先就是用2n个二进制位表示状态 蓝书上后面几题插头dp都挺烦的啊... 代码:

  4. 转 状态压缩DP

    引入 首先来说说“状态压缩动态规划”这个名称,顾名思义,状态压缩动态规划这个算法包括两个特点,第一是“状态压缩”,第二是“动态规划”. 状态压缩: 从状态压缩的特点来看,这个算法适用的题目符合以下的条 ...

  5. vijos1426兴奋剂检查(多维费用的背包问题+状态压缩+hash)

    背景 北京奥运会开幕了,这是中国人的骄傲和自豪,中国健儿在运动场上已经创造了一个又一个辉煌,super pig也不例外……………… 描述 虽然兴奋剂是奥运会及其他重要比赛的禁药,是禁止服用的.但是运动 ...

  6. 状态压缩动态规划 状压DP

    总述 状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式 很多棋盘问题都运用到了状压,同时,状压也很经常和BFS及DP连用,例题里会给出介绍 有了状态,DP就比 ...

  7. UVA11270 Tiling Dominoes(轮廓线动态规划)

    轮廓线动态规划是一种基于状态压缩解决和连通性相关的问题的动态规划方法 这道题是轮廓线动态规划的模板 讲解可以看lrj的蓝书 代码 #include <cstdio> #include &l ...

  8. 【arc093f】Dark Horse(容斥原理,动态规划,状态压缩)

    [arc093f]Dark Horse(容斥原理,动态规划,状态压缩) 题面 atcoder 有 \(2^n\) 名选手,编号为 \(1\) 至 \(2^n\) .现在这 \(2^n\) 名选手将进行 ...

  9. ZJOI 2009 多米诺骨牌(状态压缩+轮廓线+容斥)

    题意 https://www.lydsy.com/JudgeOnline/problem.php?id=1435 思路 一道很好的状压/容斥题,涵盖了很多比较重要的知识点. 我们称每两行间均有纵跨.每 ...

随机推荐

  1. 并查集(HDOJ 1856)

    并查集   英文:Disjoint Set,即“不相交集合” 将编号分别为1…N的N个对象划分为不相交集合, 在每个集合中,选择其中某个元素代表所在集合. 常见两种操作: n       合并两个集合 ...

  2. CSS3常用选择器(一)

    在 CSS 中,选择器是一种模式,用于选择需要添加样式的元素.比如最常用到的#id,.class,标签选择器. 随着CSS3到来,增加了很多新型选择器,这里就常用的做一个总结. 1.属性选择器. 在c ...

  3. NSMutableAttributedString(改变文字颜色)

    //类型 //创建一个label    UILabel *label1=[[UILabel alloc]initWithFrame:CGRectMake(130, 60,250, 150)];     ...

  4. POJ 2010 - Moo University - Financial Aid 初探数据结构 二叉堆

    考虑到数据结构短板严重,从计算几何换换口味= = 二叉堆 简介 堆总保持每个节点小于(大于)父亲节点.这样的堆被称作大根堆(小根堆). 顾名思义,大根堆的数根是堆内的最大元素. 堆的意义在于能快速O( ...

  5. POJ 2398 - Toy Storage 点与直线位置关系

    Toy Storage Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5439   Accepted: 3234 Descr ...

  6. a==null和a.equals("null")的区别

    equals 是值比较,==是比较内存 A==B,比较句柄,就是比较变量A,B的地址存放的东西,比如int A=0;String B="bbbb";那么变量A的地址方的就是0,B的 ...

  7. HttpServletRequest

    javaweb学习总结(十)——HttpServletRequest对象(一) 一.HttpServletRequest介绍 HttpServletRequest对象代表客户端的请求,当客户端通过HT ...

  8. iptables配置允许vpnserver(softether vpn)

    防火墙配置 -A INPUT -p udp -m multiport --dport ,,,, -j ACCEPT

  9. Markdown常用基本语法

    现在是我在学习Markdown时做的笔记.学完这些Markdown的基本使用已经不成问题. 1. 标题设置(让字体变大,和word的标题意思一样)在Markdown当中设置标题,有两种方式:第一种:通 ...

  10. mormot orm rest注意事项

    mORMot创建ORM RestFul,当CreateMissingTables的时候报错,搜了n多资料没搞定,后来胡乱建了个表测试了一通搞定了. ORM对应的每个数据表都需要一个ID字段并设置主键, ...