POJ 2411 Mondriaan's Dream (状压dp)
来源:互联网 发布:淘宝卖家怎么改差评 编辑:程序博客网 时间:2024/06/06 00:56
题目原文:
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!
解题思路:问题具备一定的递推性质所以采用动态规划算法。
如何制定状态,仅考虑一个格子的话,状态分析分析较为复杂。结合状态压缩dp常见的套路,将一列的格子作为一个整体,用一个正数的二进制位来表明一列格子的状态,1表示该格子被覆盖,0表示该格子尚未被覆盖。
状态: dp[i][j] -> 第i列状态为j时的填充方法
状态转移:列与列进行转移,如果两列的状态放在一起仍是合法的话,可以将前一行的 j 状态转移到后一行的 k 状态
dp[i&1][k] += dp[1-(i&1)][j];
这里关键的一步在于如何判断两个状态放在一起是否合法,这里采用dfs的方法,判断出可以与给定状态相邻的状态并记录。
具体的细节参考代码。
注:因为数据量过大采用滚动数组
AC代码:
/* @Author: wchhlbt @Date: 2017/2/20*///#include <bits/stdc++.h>#include <vector>#include <list>#include <map>#include <set>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <functional>#include <numeric>#include <utility>#include <sstream>#include <iostream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <ctime>#include <cstring>#include <limits>#include <climits>#include <cstdio>#define Fori(x) for(int i=0;i<x;i++)#define Forj(x) for(int j=0;j<x;j++)#define maxn 2100#define inf 0x3f3f3f3f#define ONES(x) __builtin_popcount(x)using namespace std;typedef long long ll ;const double eps =1e-8;const int mod = 1000000007;typedef pair<int, int> P;const double PI = acos(-1.0);int dx[4] = {0,0,1,-1};int dy[4] = {1,-1,0,0};int n,m;bool vis[maxn][maxn];//记录状态是否可以转移的矩阵ll dp[2][maxn];//使用滚动数组 dp[i][j] -> 第i列状态为j时有多少种方法ll ans[15][15];void dfs(int x, int i, int z){//x 当前状态 i当前行数 z预期状态 //通过递归判断两个状态是否可以转移并记录 if(i>n) { vis[x][z]=true; return; } if(x & (1<<(i-1))) { dfs(x,i+1,z); if(i<n && (x&(1<<i))) dfs(x,i+2,z+(1<<(i-1))+(1<<i)); } else dfs(x,i+1,z+(1<<(i-1)));}int main(){ //freopen("test.txt","r",stdin); ios_base::sync_with_stdio(false); cin.tie(0); while(cin>>n>>m && n+m){ if((n*m) & 1){ cout << 0 << endl; continue; } if(ans[n][m]){ cout << ans[n][m] << endl; continue; } if(m<n) swap(m,n);//让n尽可能的小,提高效率 ll up = (1<<n); memset(dp,0,sizeof(dp)); memset(vis,0,sizeof(vis)); for(int i = 0; i<up; i++) dfs(i,1,0); for(int i = 0; i<up; i++)//记录初始状态,将前一列都放满 dp[1][i] = vis[up-1][i]; for(int i = 2; i<=m; i++){ memset(dp[i&1],0,sizeof(dp[i&1]));//及时清空本列数组 for(int j = 0; j<up; j++){ for(int k = 0; k<up; k++){ if(vis[j][k])//如果可以从状态 j 转移到状态 k dp[i&1][k] += dp[1-(i&1)][j]; } } } cout << dp[m&1][up-1] << endl;//最终状态是第m列全部放满的情况 所以 j = (1<<n)-1 ans[n][m] = ans[m][n] = dp[m&1][up-1];//记忆化处理 } return 0;}
- POJ 2411 Mondriaan's Dream (状压DP)
- Mondriaan's Dream - POJ 2411 状压dp
- POJ 2411 Mondriaan's Dream (状压DP)
- poj 2411 Mondriaan's Dream 状压dp
- poj 2411 Mondriaan's Dream(状压dp)
- POJ 2411 Mondriaan's Dream 状压dp
- POJ 2411 Mondriaan's Dream ( 状压DP )
- Mondriaan's Dream POJ - 2411 状压DP
- POJ 2411 Mondriaan's Dream (状压dp)
- POJ 2411 Mondriaan's Dream 状压dp
- [POJ 2411]Mondriaan's Dream:状压DP
- POJ 2411 Mondriaan's Dream (状压DP)
- poj 2411 Mondriaan's Dream 【状压dp】
- POJ 2411 Mondriaan's Dream(状压DP)
- poj 2411 Mondriaan's Dream(状压DP)
- POJ 2411 Mondriaan's Dream(状压 dp)
- POJ 2411 Mondriaan's Dream (状压DP)
- 【POJ 2411】Mondriaan's Dream(状压dp)
- C#怎样判定txt档案的编码格式
- 用户标签系统 数据库设计
- 机器学习:线性回归、局部加权线性回归、岭回归、前向逐步回归
- Tomcat 6.0/webapps/项目名/WEB-INF/classes下为空
- 1099. Build A Binary Search Tree
- POJ 2411 Mondriaan's Dream (状压dp)
- QT数据库插件——Qkingbase
- UDEV管理RAC共享存储
- 是否允许分配伪终端解决
- 纯js实现html转pdf
- Git&GitHub学习笔记之(三)Git向GitHub提交代码
- 甲骨文预科学习第一次
- 机器学习之KNN 算法
- 快速排序/quickSort