POJ 2411 Mondriaan's Dream【状压DP】

题目来源:http://poj.org/problem?id=2411
POJ 2411 Mondriaan's Dream【状压DP】_第1张图片
POJ 2411 Mondriaan's Dream【状压DP】_第2张图片
★我一开始还以为是找规律的题(不过那时候我也没学 状压DP) 现在算是第二题吧

题意:

你有长宽为2 1 的矩形,问有多少种放法组成一个n*m的大矩形

思路:

把大矩形分为1*1的小正方形来看,然后每一行都会有m个单元最多11个,我们可以用二进制来表示每一行
然后每一层都只受他上一层的影响,而第一层我们可以枚举,然后就可以慢慢推出来了
dp[ i ][ j ] 指 前 i 层的 前 i-1 层放满且第i层状态为 j 的 方法数
当第i层 状态为 100001时 表示 第一个和第六个被占过了
所以下一层就从状态 011110 开始推
详见代码

代码:

#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1<<15;
const int mod=1e9+7;
typedef long long LL;
LL n,m,tmp;
LL dp[20][1<<15];
void hhh(int k,int x,int pos)
{
    if(pos==m) {dp[k][x]+=tmp; return ;}
    hhh(k,x,pos+1);
    if(pos<=m-2&&!(x&1<<pos)&&!(x&(1<<pos+1)))
        hhh(k,x|1<<pos|1<<pos+1,pos+2);
}
int main()
{
    while(~scanf("%lld%lld",&n,&m)&&(n||m)){
        memset(dp,0,sizeof dp);
        tmp=1;
        hhh(1,0,0);
        for(int i=2;i<=n;i++){
            for(int j=0;j<(1<<m);j++){
                if(dp[i-1][j]) tmp=dp[i-1][j];
                else continue;
                hhh(i,~j&((1<<m)-1),0);
            }
        }
        cout<<dp[n][(1<<m)-1]<<endl;
    }
    return 0;
}

你可能感兴趣的:(动态规划)