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. 【转载】H264--2--语法及结构

    名词解释 场和帧 :    视频的一场或一帧可用来产生一个编码图像.在电视中,为减少大面积闪烁现象,把一帧分成两个隔行的场. 片:             每个图象中,若干宏块被排列成片的形式.片分为 ...

  2. 在本地机器上能访问tomcat,远程机器访问不了的解决方法

    问题描述:在测试服务器上搭建了一个tomcat,在测试服务器上能用ip打开tomcat.我用自己的机器能远程桌面能登录到测试服务器上,但在自己的机器上无法通过ip来访问测试服务器上的tomcat. 解 ...

  3. linux配置的问题

    1 从系统设置-文本设置中把双拼删掉 2 通过sudo passwd root 修改root密码 3 通过su获取root权限 4 通过sudo pppoeconf输入宽带帐号密码 5 把更新源修改成 ...

  4. Tara's Beautiful Permutations 组合数学

    https://www.hackerrank.com/contests/hourrank-15/challenges/taras-beautiful-permutations 首先先统计一下个数为2的 ...

  5. ZOJ 2770火烧连营——差分约束

    偶尔做了一下差分约束. 题目大意:给出n个军营,每个军营最多有ci个士兵,且[ai,bi]之间至少有ki个士兵,问最少有多少士兵. ---------------------------------- ...

  6. ssh搭建后的简化

    关于ssh如何搭建还有不懂得朋友可以参考以下网址:http://www.cnblogs.com/LarryBlogger/p/5841446.html 在这里我就不重复再讲了! ssh搭建后的简化 简 ...

  7. Java 基础知识总结 (二、基本数据类型)

    二.基本数据类型 java基本数据类型只能先声明后使用 boolean  true/false char 16-bit unicode character byte 8-bit integer sho ...

  8. Samba服务器搭建配置

    本次环境: 服务端-centos6.8-192.168.2.200 客户端1-centos6.8-192.168.2.201 客户端2-Windows7-192.168.2.104 假设条件如下: 使 ...

  9. 分布式日志1 用c#的队列写日志

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  10. 复利test

    因为上节课老师有给我们讲了单元测试的概念及其基本操作,我就对我之前的复利计算器进行了改进和测试.因为从控制台的简单输入输出对单元测试来说不够完善,便参考了其他同学的优秀编程又重新写了一个复利计算器的框 ...