POJ 2411 Mondriaan's Dream
2016-04-20 20:17
393 查看
题目链接:http://poj.org/problem?id=2411
题意:用1×2的砖铺满m×n的矩形,问一共有多少种铺法。
思路:状态压缩DP, 只有两种铺法,横着铺和竖着铺。我们按行dp,那么就要把每一行的状态表示出来。对于横着铺,可以用两个相邻的1来表示;对于竖着放,我们将上面那行的位置记0,下面那行的位置记1,也就是竖着的0 1表示。先确定第一行的状态(按照状态规定,第一行的1都是横着放得来的)所以如果存在相邻的1,它们的数量必定是偶数个。接着我们枚举相邻两行的状态进行转移,当前行s1,上一行s2:s1放完的时候s2应该也被填充满了,所以(s1 | s2) 一定是满的。其次再考虑两行的兼容问题,(s1 & s2)为第一行的可行状态时才兼容,因为所有竖着放的位置会被忽略(1
& 0),只剩下横着放的位置。所以最后的答案应该是dp
[(1<<m)-1],最后一行一定要放满。
题意:用1×2的砖铺满m×n的矩形,问一共有多少种铺法。
思路:状态压缩DP, 只有两种铺法,横着铺和竖着铺。我们按行dp,那么就要把每一行的状态表示出来。对于横着铺,可以用两个相邻的1来表示;对于竖着放,我们将上面那行的位置记0,下面那行的位置记1,也就是竖着的0 1表示。先确定第一行的状态(按照状态规定,第一行的1都是横着放得来的)所以如果存在相邻的1,它们的数量必定是偶数个。接着我们枚举相邻两行的状态进行转移,当前行s1,上一行s2:s1放完的时候s2应该也被填充满了,所以(s1 | s2) 一定是满的。其次再考虑两行的兼容问题,(s1 & s2)为第一行的可行状态时才兼容,因为所有竖着放的位置会被忽略(1
& 0),只剩下横着放的位置。所以最后的答案应该是dp
[(1<<m)-1],最后一行一定要放满。
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <cstdlib> #include <iostream> #include <algorithm> #include <stack> #include <map> #include <set> #include <vector> #include <sstream> #include <queue> #include <utility> using namespace std; #define rep(i,j,k) for (int i=j;i<=k;i++) #define Rrep(i,j,k) for (int i=j;i>=k;i--) #define Clean(x,y) memset(x,y,sizeof(x)) #define LL long long #define ULL unsigned long long #define inf 0x7fffffff #define mod %100000007 int n , m; bool can[1<<11]; LL ans[12][12]; LL dp[12][1<<11]; bool check( int state ) { int x = 0; while( state ) { if ( state & 1 ) x++; else { if ( x & 1 ) return false; x = 0; } state>>=1; } return !(x & 1); } bool f(int x1,int x2,int aim) { if ( (x1 | x2) != aim ) return false; return can[ x1 & x2 ]; } void init() { Clean(can,false); Clean(ans,-1); int uplim = 1<<11; rep( i , 0 , uplim - 1) if ( check(i) )can[i] = true; } int main() { init(); while( ~scanf("%d%d",&n,&m) ) { if ( m+n == 0 ) break; if ( (n*m) & 1 ) { puts("0"); continue; } if ( n < m ) swap(n,m); if ( ans [m] != -1 ) { printf("%lld\n",ans [m]); continue; } Clean(dp,0); int uplim = 1<<m; rep(i,0,uplim-1) if ( can[i] ) dp[1][i] = 1; rep(i,2,n) rep(j,0,uplim-1) rep(k,0,uplim-1) if ( f(j,k,uplim-1) ) dp[i][j]+=dp[i-1][k]; printf("%lld\n",dp [uplim-1]); ans [m] = dp [uplim-1]; } return 0; }
相关文章推荐
- webservice 使用vs2005生成代理
- bzoj4540: [Hnoi2016]序列
- [LintCode] 快速幂 Fast Power
- 电商中刮刮卡的实现
- NodeJS 单线程 和java 多线程
- 自己实现简单shell的小例子
- Simpliciti协议栈移植笔记一
- Java 字节流与字符流的区别
- 跟王老师学接口:(五)实例:对电子宠物系统进行重构
- hdu 2602 Bone Collector 基础01背包
- 进制转换---由任意进制转为任意进制---NOJ1592
- SVN常见错误
- python中函数的总结之三
- python中函数的总结之三
- C#线程同步的几种方法
- 关于EnumerateObjectsUsingBlock和for-in之间的较量
- 内存管理
- Visual studio 2010出现“error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏”解决方式
- python中函数的总结之三
- HDU 1808(鸽巢原理)