poj3311 动态规划 轮廓线 或者状态压缩
来源:互联网 发布:js字符串相等 编辑:程序博客网 时间:2024/06/05 11:14
题目大致意思就是给你1*2的矩形砖块 让你填充满h*w的矩形区域 有多少种填充方法?hw的值小于12,
两种解法:
1. 状态压缩dp
思路很简单,对于每一个格子,我们考虑这个格子上面我们是竖向放砖块还是横向放砖块,如果横向放 我们就有横着的两个11表示,竖向放我们就用竖着的01表示,那么每一行就可以表示为一个状态,在其中一行的时候,首先判断当前行的状态是否符合上一行的要求,即上一行为0的地方这一行这个位置必须是1,上一行为1的地方这一行这个位置就可以随便,然后检查一下当前行是否合法就可以了,合法指的是这一行与上一行的值按位与,得到的值的二进制中的连续1的个数都是偶数个。具体看代码
#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<string>#include<set>#include<map>#include<queue>#include<stack>#include<cstring>using namespace std;#define LL long longbool isRight[1<<13];bool isOk(int s){ int cnt = 0; while(s) { if(s&1) { cnt++; } else { if(cnt&1)return false; cnt = 0; } s>>=1; } if(cnt&1)return false; return true;}int main(){ memset(isRight,false,sizeof(isRight)); for(int i = 0;i<1<<13;i++) { if(isOk(i)) { isRight[i] = true; } } int h,w; while(scanf("%d%d",&h,&w) && h && w) { LL dp[15][1<<13]; memset(dp,0,sizeof(dp)); for(int i = 0;i<(1<<w);i++) { if(isRight[i]) { dp[0][i] = 1; } } for(int i = 1;i<h;i++) { for(int j = 0;j<(1<<w);j++) { for(int k = 0;k<(1<<w);k++) { int nk = ((1<<w)-1)^k; if((nk&j) != nk)continue; // 上面两行代码是判断当前状态是否符合上面一行的要求 用位运算 上一行取反 然后异或当前行判断是否相等 判断 if(isRight[j&k]) { dp[i][j] += dp[i-1][k]; } } } } //cout << isRight[7] << endl; printf("%lld\n",dp[h-1][(1<<w)-1]); } return 0;}
- 轮廓线动态规划
这里有一个非常好的题解
简单的说一下自己的理解吧,轮廓线的的转移类似一个蛇在图上移动,每次用下一个格子和上一个轮廓线(蛇)来转移,在新的格子有两种放放法,例如以题解中的o格 可以放砖在K4O上 即上放,或者k0O即左放
代码:
#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<string>#include<set>#include<map>#include<queue>#include<stack>#include<cstring>using namespace std;#define LL long longint main(){ int w,h; while(scanf("%d%d",&h,&w) && w && h) { LL dp[15][1<<13]; memset(dp,0,sizeof(dp)); dp[0][(1<<w)-1] = 1; int cur = 0; for(int i = 0;i<h;i++) { for(int j = 0;j<w;j++) { for(int k = 0;k<(1<<w);k++) { // 不放 直接左移 但是保证上一个轮廓线首位为1 if(k & (1<<w-1)) dp[!cur][(k<<1)&(1<<w)-1] += dp[cur][k]; // 上放 上一个轮廓线首位为0不然放不了 if(i && !((1<<(w-1))&k)) dp[!cur][(k<<1)|1] += dp[cur][k]; // 左放 保证上一个 轮廓线尾部为0 然后左放 if(j && !(k&1) && (k & (1<<w-1))) { int id = (((k|1)<<1)|1) & (1<<w)-1; dp[!cur][id] += dp[cur][k]; } } memset(dp[cur],0,sizeof(dp[cur])); cur = !cur; } } printf("%lld\n",dp[cur][(1<<w)-1]); } return 0;}
两个代码时间差别非常大 状态压缩用了579ms 轮廓线用了79ms
阅读全文
0 0
- poj3311 动态规划 轮廓线 或者状态压缩
- poj3311 状态压缩
- poj3311 状态压缩dp
- 《挑战程序设计竞赛》3.4.1 动态规划-状态压缩DP POJ3311 2686 2411 2441 3254 2836 1795 3411(2)
- POJ2411 Mondriaan's Dream (轮廓线动态规划典型例题 以及用状态压缩逐行深搜推的方法)
- 状态压缩动态规划
- 状态压缩动态规划
- 状态压缩动态规划
- 状态压缩动态规划
- 状态压缩动态规划
- 动态规划!状态压缩
- 状态压缩动态规划
- 轮廓线动态规划
- POJ3311(状态压缩DP+Floyd)
- poj3311(状态压缩dp)
- 【状态压缩】【动态规划】电子竞技
- 【状态压缩】【动态规划】坑爹题
- 什么是状态压缩动态规划
- Android的button事件
- Oracle PL/SQL的存储过程
- react-native笔记
- Boost Thread使用
- 关于Java的File.separator
- poj3311 动态规划 轮廓线 或者状态压缩
- [Leetcode] 301. Remove Invalid Parentheses 解题报告
- 在vue中使用sass的配置的方法
- 微软100题-009
- Linux快捷键总结
- Java中的static关键字解析
- Android--------在Fragment中通过MVP模式用Okhttp进行数据请求
- 有关java web工程降级jdk遇到的问题
- 归并排序和快速排序