Mondriaan's Dream状压DP
Posted qseer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mondriaan's Dream状压DP相关的知识,希望对你有一定的参考价值。
题意:
给定一个 n*m 的矩形,用1*2的方块填充的所有方案数
Sample Input
1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0
Sample Output
1
0
1
2
3
5
144
51205
思路:
像这样看上去就不会做的题目数据范围一般都不大(因为要用状压呀,大了能存的下吗?)
而且显然答案会很大,所以记得开 long long
正题----
我们可以一行一行地看,对于上一行地情况,可以是横着的也可以是竖着的,横着的对我们当前这一行的状态无影响,关键是竖着的方块我们在这一行必须给它接上。
我们用长度为 m 的二进制数来表示状态
状态为竖着摆时的上半截,状态为 1 ,否则为 0
我们考虑当前这一行,如果上一行是1,我必须接上下半截,状态为 0 ;如果是 0 ,那我这一行就可以随便摆
设当前状态为 j,上一行状态为 k
所以必定满足:
- j&k==0
- j | k 状态中连续的 0 必须有偶数个
第二条也很显然,我们活下来的是什么状态呢?1表示竖着,0,表示横着且连续,如果 0 是奇数个,就不符合要求
所以我们就先需要预处理出合法的情况
code
#include<stdio.h>
#include<algorithm>
using namespace std;
int n,m;
long long f[12][1<<11];
bool ins[1<<11];
int main()
{
while(scanf("%d%d",&n,&m) && n && m) {
int mix=(1<<m);
for(int i=0;i<mix;++i) {
bool cnt=0,flag=0;
for(int j=0;j<m;++j) {
if(i>>j & 1) flag|=cnt,cnt=0;
else cnt^=1;
}
ins[i]=flag|cnt?0:1;
}
f[0][0]=1;
for(int i=1;i<=n;++i) {
for(int j=0;j<mix;++j) {
f[i][j]=0;
for(int k=0;k<mix;++k) {
if((j&k)==0 && ins[j|k])
f[i][j]+=f[i-1][k];
}
}
}
printf("%lld
",f[n][0]);
}
return 0;
}
以上是关于Mondriaan's Dream状压DP的主要内容,如果未能解决你的问题,请参考以下文章
[Poj2411]Mondriaan's Dream(状压dp)(插头dp)
POJ 2411 Mondriaan's Dream -- 状压DP
POJ 2411 Mondriaan's Dream ——状压DP 插头DP