状压dp Mondriaan's Dream poj2411
来源:互联网 发布:sql用于授权语句的是 编辑:程序博客网 时间:2024/06/08 00:23
超经典的一道题目,实现这题的方法也有很多种
1.利用DFS建立矩阵,然后通过快速矩阵幂得到答案(运用于min(m,n)比较小,但是max(m,n)非常大的情况)
2.利用dp状压解决
第一种在我的另一篇博客里有
http://blog.csdn.net/qwb492859377/article/details/47138821
我们在这里讨论第二种方法。
刘汝佳的算法训练指南中384页介绍了一种复杂度O(mn*2^m)的方法,这个复杂度实在是太小了!
我对着上面敲结果只用了32ms就过了这题,然后花了很久才看懂(蒟蒻)
他的状态并不是一整行一整行的,,所以一开始我就陷入了误圈。
第二,,他代码里有个1<<m,我一直没搞清楚,到底他的下标是从0开始还是从1开始,怎么会出现1<<m呢,其实这是上一次的1<<m-1,因为他把状态先左移过一次-_-....
我根据我的理解讲下代码
(i,j)表示以这个格子为右下角,要不要放骨牌以及放那种骨牌. k表示在(i,j)之前的连续m个方块的状态,0表示没放,1表示已经放了,其中靠近(i,j)的下标是0
先枚举,i再枚举j,最后枚举k,也就是红色表示的区域
如果(i,j)不放,那么它上面那一个就必须已经放过了,换句话说,只有k&(1<<(m-1)) ,k才有资格将状态转移到新的状态(k<<1)^(1<<m)
这个状态就是左移后,把以前的第一位去掉,然后在最后面补上一个0,相当于红色区域全部向右挪了一个单位。
如果(i,j)放竖直的骨牌,那么i不能为0,且!k&(1<<(m-1))满足,才能考虑把k状态转移到新的状态k << 1 | 1去
如果(i,j)放横向的骨牌,那么j不能为0,且!(k&1)&&(1<<(m-1)) 也就是k的最后一个要是空着的,而且(i,j)上面一个必须是1。这样才能横向放后上面的不会存在空着的。刚开始我还在思考,应该(i-1,j-1)也应该要是1才可以把,,但是后来想了一下,那个位置一定会是1,否则(i,j)左边那个位置就不可能是0了,因为只能通过第一种情况转移过来
所以当满足这些条件时,k能转移到新状态(k<<1)^(1<<m)|3上来
语言表达能力有限,,,来看代码把,,感觉刘汝佳那份代码虽然写起来很工整清晰,反而有些地方变得很难理解了
然后dp利用滚动数组,得到的状态向后更新答案的方式,就能解决了
#include<cstdio>#include<cmath>#include<cstring>#include<queue>#include<vector>#include<functional>#include<algorithm>using namespace std;typedef long long LL;typedef pair<int, int> PII;const int MX = 3000 + 5;const int INF = 0x3f3f3f3f;int m, n;LL dp[2][MX];int main() { //freopen("input.txt","r",stdin); while(~scanf("%d%d", &m, &n), m + n) { memset(dp, 0, sizeof(dp)); if(m > n) swap(m, n); int cur = 0, nxt = 1; dp[cur][(1 << m) - 1] = 1; for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++) { memset(dp[nxt], 0, sizeof(dp[nxt])); for(int k = 0; k < (1 << m); k++) { if(k & (1 << (m - 1))) dp[nxt][(k << 1) ^ (1 << m)] += dp[cur][k];//不放 if(i && !(k & (1 << (m - 1)))) dp[nxt][k << 1 | 1] += dp[cur][k];//竖着放 if(j && !(k & 1) && (1 << (m - 1))) dp[nxt][(k << 1) ^ (1 << m) | 3] += dp[cur][k];//横着放 } swap(cur, nxt); } } printf("%I64d\n", dp[cur][(1 << m) - 1]); } return 0;}
- poj2411 mondriaan's dream 状压dp
- poj2411--Mondriaan's Dream(状压dp+dfs)
- 状压dp Mondriaan's Dream poj2411
- poj2411 Mondriaan's Dream 状压dp
- [POJ2411] Mondriaan's Dream 状压dp
- poj2411 Mondriaan's Dream--状压dp
- POJ2411:Mondriaan's Dream(状压dp)
- POJ2411 Mondriaan's Dream 【状压dp】
- poj2411 Mondriaan's Dream(状压dp)
- poj2411 Mondriaan's Dream(状压dp)
- 【状压DP】Mondriaan's Dream POJ2411 - 基础状压
- poj2411 Mondriaan's Dream 状态压缩dp
- poj2411 Mondriaan's Dream 状态压缩dp
- poj2411 Mondriaan's Dream 插头dp做法
- POJ2411 Mondriaan's Dream(压缩DP)
- POJ2411-Mondriaan's Dream-状态dp
- 【poj2411】Mondriaan's Dream 状态压缩dp
- poj2411 Mondriaan's Dream【插头dp】
- 【PHP】php通过javascript判断不同设备分辨率来调用不同的css class
- ubuntu 下安装jdk 和配置java环境变量
- HDU 4283 You Are the One (区间DP)
- Leetcode# 82 Remove Duplicates from Sorted List II
- django环境搭建
- 状压dp Mondriaan's Dream poj2411
- 虚析构函数(√)、纯虚析构函数(√)、虚构造函数(X)
- C语言之函数调用18—多字符串排序
- HDU 3853 向下向右找出口问题-期望dp
- Activity技巧三重奏之二:随时随地的退出程序
- 使用rpmbuild来创建自己的RPM
- hdu1057
- index
- 单词进行倒置