POJ 2411 Mondriaan's Dream (状态压缩DP)

题意:给定一个矩阵,只能放1*2的木块,问将这个矩阵完全覆盖的不同放法有多少种。

分析:横着放为11,竖着放为竖着的01,所以判断相邻两行是否被完全覆盖:只需判断两行状态合集(j | k)是否是满的, 两种状态是否有冲突(j & k)。

第一行直接预处理就行。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
__int64 dp[12][1 << 11]; //横着放为11,竖着放为0
                       //                    1
int buff[1 << 11];
int n,m;
__int64 ans;

bool judge(int b) {
    bool flag = 1;
    while(b) {
        if(b & 1) {
            if((b >> 1) & 1) b = b >> 2;
            else {
                flag = 0;
                b = b >> 1;
            }
        } else b = b >> 1;
        if(flag == 0) return 0;
    }
    return flag;
}
void getbuff() {
    int total = 1 << 11;
    for(int i=0; i<total; i++) {
        if(judge(i)) {
            buff[i] = 1;
        }
    }
}

void solve() {
    int total = 1 << m;
    for(int i=1; i<n; i++) { //最后一行一定全是1
        for(int j=0; j<total; j++) {
            for(int k=0; k<total; k++) {
                if((j | k) == total-1 && buff[(j & k)]) {
                    dp[i][j] += dp[i-1][k];
                }
            }
        }
    }
    ans = dp[n-1][total-1];
}

int main() {
    getbuff();
    while(scanf("%d%d",&n,&m) ) {
        if(n == 0 && m == 0 ) break;
        if(n == 1) {
            if(m % 2 == 0) printf("1\n");
            else printf("0\n");
            continue;
        }
        int total = 1 << m;
        memset(dp,0,sizeof(dp));
        for(int i=0; i<total; i++) {
            if(buff[i]) dp[0][i] = 1;
        }
        ans = 0;
        solve();
        printf("%I64d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(POJ 2411 Mondriaan's Dream (状态压缩DP))