[ACM_动态规划] 轮廓线动态规划——铺放骨牌(状态压缩1)
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 |
Sample Output 1 |
![]() |
Input
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
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)的更多相关文章
- 动态规划——用二进制表示集合的状态压缩DP
动态规划当中有非常常见的一个分支--状态压缩动态规划,很多人对于状态压缩畏惧如虎,但其实并没有那么难,希望这文章能带你们学到这个经典的应用. 二进制表示状态 在讲解多重背包问题的时候,我们曾经讲过二进 ...
- UVa 11270 铺放骨牌(轮廓线DP)
https://vjudge.net/problem/UVA-11270 题意: 用1×2骨牌覆盖n×m棋牌,有多少种方法? 思路: 这道题目是典型的轮廓线DP题. 所谓轮廓线DP,就是以整行整列为状 ...
- 铺放骨牌 uva11270
题解: 插头dp裸题 没什么好说的啊就是n个二进制位表示状态 相比原先就是用2n个二进制位表示状态 蓝书上后面几题插头dp都挺烦的啊... 代码:
- 转 状态压缩DP
引入 首先来说说“状态压缩动态规划”这个名称,顾名思义,状态压缩动态规划这个算法包括两个特点,第一是“状态压缩”,第二是“动态规划”. 状态压缩: 从状态压缩的特点来看,这个算法适用的题目符合以下的条 ...
- vijos1426兴奋剂检查(多维费用的背包问题+状态压缩+hash)
背景 北京奥运会开幕了,这是中国人的骄傲和自豪,中国健儿在运动场上已经创造了一个又一个辉煌,super pig也不例外……………… 描述 虽然兴奋剂是奥运会及其他重要比赛的禁药,是禁止服用的.但是运动 ...
- 状态压缩动态规划 状压DP
总述 状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式 很多棋盘问题都运用到了状压,同时,状压也很经常和BFS及DP连用,例题里会给出介绍 有了状态,DP就比 ...
- UVA11270 Tiling Dominoes(轮廓线动态规划)
轮廓线动态规划是一种基于状态压缩解决和连通性相关的问题的动态规划方法 这道题是轮廓线动态规划的模板 讲解可以看lrj的蓝书 代码 #include <cstdio> #include &l ...
- 【arc093f】Dark Horse(容斥原理,动态规划,状态压缩)
[arc093f]Dark Horse(容斥原理,动态规划,状态压缩) 题面 atcoder 有 \(2^n\) 名选手,编号为 \(1\) 至 \(2^n\) .现在这 \(2^n\) 名选手将进行 ...
- ZJOI 2009 多米诺骨牌(状态压缩+轮廓线+容斥)
题意 https://www.lydsy.com/JudgeOnline/problem.php?id=1435 思路 一道很好的状压/容斥题,涵盖了很多比较重要的知识点. 我们称每两行间均有纵跨.每 ...
随机推荐
- delegate事件绑定
为了代码的健壮性,绑定事件之前先解绑再进行绑定. var _$div = $("#id");_$div.undelegate("click mouseover mouse ...
- {C#}{GDI+}各种C#,GDI+的资料
GDI+各种功能: http://www.cnblogs.com/08shiyan/category/253906.html 字体:http://blog.sina.com.cn/s/blog_7c7 ...
- linux系统各目录存储的文件类型
/etc 存储各种配置文件 /etc/init.d/ 目录下包含许多系统各种服务的启动和停止脚本.具体可见:http://blog.csdn.net/gongweijiao/article/detai ...
- SQL Server 查询处理中的各个阶段(SQL执行顺序)
SQL 不同于与其他编程语言的最明显特征是处理代码的顺序.在大数编程语言中,代码按编码顺序被处理,但是在SQL语言中,第一个被处理的子句是FROM子句,尽管SELECT语句第一个出现,但是几乎总是最后 ...
- Java值传递和引用传递详细解说
前天在做系统的时候被Java中参数传递问题卡了一下,回头查阅了相关的资料,对参数传递问题有了新的了解和掌握,但是有个问题感觉还是很模糊,就是 Java中到底是否只存在值传递,因为在查阅资料时,经常看到 ...
- 自动获取socket链接状态
C# TcpClient在连接成功后无法检测连接状态,即使对方关闭了网络连接.以下扩展可检测连接状态: static class TcpClientEx { public static bool Is ...
- 在线学习体验大PK 云智慧发布在线教育网站性能监测报告
互联网不但改变了我们的生活.娱乐和消费方式,也推动各行各业进行着快速变革,越来越多的职场人士必须通过不断的学习.充电才能跟上行业发展的步伐,获得职业的提升,而这也引发了国内教育市场的爆炸式发展.据统计 ...
- 线程池pool
参考链接 http://www.open-open.com/lib/view/open1415453575730.html 参考配置 http://www.cnblogs.com/linjiqin/a ...
- MySQL里的wait_timeout
如果你没有修改过MySQL的配置,缺省情况下,wait_timeout的初始值是28800. wait_timeout过大有弊端,其体现就是MySQL里大量的SLEEP进程无法及时释放,拖累系统性能, ...
- Deep Learning(1)-Introduction学习总结
学习DL搁置很久了,终于下定决心开始咯~~ Deep Learning(Ian Goodfellow&&Yoshua Bengio&&Aaron Courville)- ...