POJ2411 Mondriaan's Dream(状态压缩DP)
2015-11-16 22:14
330 查看
人生第一道状态压缩DP,我这个弱渣想了N天终于弄懂了◑﹏◐
题目大意:求1*2的地板填满n*m的砖块有多少种不同的方法
思路:位运算+DFS+状态压缩。
当高度和宽度都为奇数时答案为0。
对于每一个位置,我们有三种放置方法:
1. 竖直放置
2. 水平放置
3. 不放置
d为当前列号 ,初始化d, now, pre都为0;对应以上三种放置方法,now, pre的调整为:
1. d = d + 1, now << 1 | 1, pre << 1;
2. d = d + 2, now << 2 | 3, pre << 2 | 3;
3. d = d + 1, now << 1, pre << 1 | 1;
先就第一种情况解释一下,另外的两种情况可以类推
now<<1|1即为把s1的二进制表示后面加上一个1,对就于本题来说就是(d+1)列上放
置,pre<<1即为把s2的二进制表示后面加上一个0,对于本题来说就是(d+1)列上不放置。
now对应于本行的状态,pre对应于上一行的状态,能竖直放置意味着上一行的(d+1)列是空着的,因此此时上一行的状态为pre<<1,同时竖
置放置了之后,则本行(d+1)行放置了东西,状态于是变为now<<1|1;
当d = w时保存状态
对于初始时的f值,可以假设第0行全满,第一行只有两种放法:
1. 水平放置 d = d + 2, s << 2 | 3;
2. 不放置 d = d + 1, s << 1;
最后只要判断h行是否全为1就行了,只取最后一行全为1的答案,也就是(1<
题目大意:求1*2的地板填满n*m的砖块有多少种不同的方法
思路:位运算+DFS+状态压缩。
当高度和宽度都为奇数时答案为0。
对于每一个位置,我们有三种放置方法:
1. 竖直放置
2. 水平放置
3. 不放置
d为当前列号 ,初始化d, now, pre都为0;对应以上三种放置方法,now, pre的调整为:
1. d = d + 1, now << 1 | 1, pre << 1;
2. d = d + 2, now << 2 | 3, pre << 2 | 3;
3. d = d + 1, now << 1, pre << 1 | 1;
先就第一种情况解释一下,另外的两种情况可以类推
now<<1|1即为把s1的二进制表示后面加上一个1,对就于本题来说就是(d+1)列上放
置,pre<<1即为把s2的二进制表示后面加上一个0,对于本题来说就是(d+1)列上不放置。
now对应于本行的状态,pre对应于上一行的状态,能竖直放置意味着上一行的(d+1)列是空着的,因此此时上一行的状态为pre<<1,同时竖
置放置了之后,则本行(d+1)行放置了东西,状态于是变为now<<1|1;
当d = w时保存状态
对于初始时的f值,可以假设第0行全满,第一行只有两种放法:
1. 水平放置 d = d + 2, s << 2 | 3;
2. 不放置 d = d + 1, s << 1;
最后只要判断h行是否全为1就行了,只取最后一行全为1的答案,也就是(1<
#include <iostream> #include <string> #include <cstring> #include <stdio.h> #include <cstdlib> #include <map> #include <set> #include <vector> #include <queue> #include <functional> #include <algorithm> #include <cmath> #include <assert.h> #include <stack> using namespace std; #define maxn 1<<12 int h,w,p,q; long long dp[2][maxn]; void dfs(int col,int now,int pre) //now当前行状态,pre前一行状态 { if(col==w) //col已经移到当前行最左边一列 { dp[q][now]+=dp[p][pre]; return; } if(col+1<=w) { dfs(col+1,now<<1,pre<<1|1); //不放 ,故而pre<<1|1,即将当前行的下一列由0变1 //当前行在下一个dfs变成前一行,即pre dfs(col+1,now<<1|1,pre<<1); //竖放 //当下一行行的下一列由0变1(now<<1|1) } if(col+2<=w) dfs(col+2,now<<2|3,pre<<2|3); //横放 //3二进制为100,或运算将当前行的下一行同一列由0变成1 } void solve() { int i; if((( w * h ) & 1) ) //&1相当于%2,但是与运算更快 { printf("0\n"); return; } memset(dp,0,sizeof(dp)); p=0; dp[0][(1<<w)-1]=1; for(i=1;i<=h;i++) { q=p^1; //滚动数组,p,q轮替交换,p是上一行,q是当前行 dfs(0,0,0); memset(dp[p],0,sizeof(dp[0])); p=q; } printf("%lld\n",dp[q][(1<<w)-1]); } int main() { while(~scanf("%d%d",&h,&w)&&(w||h)) { if(w>h)swap(w,h); solve(); } return 0; }
相关文章推荐
- C#使用DeflateStream解压缩数据文件的方法
- C#调用WinRar执行rar、zip压缩的方法
- C#实现页面GZip或Deflate压缩的方法
- C#使用iCSharpcode进行文件压缩实现方法
- C#实现压缩HTML代码的方法
- Asp.net在线备份、压缩和修复Access数据库示例代码
- 使用UglifyJS合并/压缩JavaScript的方法
- 高性能WEB开发 JS、CSS的合并、压缩、缓存管理
- 脚本分析、压缩、混淆工具 JSA新版本发布,压缩效率提高大约10%
- 发布一个高效的JavaScript分析、压缩工具 JavaScript Analyser
- PHP实现图片压缩的两则实例
- 在IIS上启用Gzip压缩 (HTTP压缩)第1/3页
- javascript实现的样式表(CSS) 格式整理与压缩
- php zlib压缩和解压缩swf文件的代码
- YUI Compressor压缩JavaScript原理及微优化
- Nginx中的Gzip压缩配置介绍
- python zip文件 压缩
- Tomcat配置gzip压缩提高浏览网站的速度
- C#实现的文件压缩和解压缩类
- CSS代码格式化和压缩的方法与技巧