poj 2411 用1x2填充n*m 状态压缩DP

来源:互联网 发布:软件应届生求职怎么样 编辑:程序博客网 时间:2024/05/20 20:18
/*
dp[i][s]为当i-1行满时,i行的状态是s的方案数
i状态是now_s,i-1状态是pre_s,在第i行横向扫描时,
1.
一个位置若是横着放,则下一个状态是now_s<<2|3
且对应i-1的状态是pre_s<<2|3 (上一行这个两个位置必不为空才能不放)
2.
一个位置若是竖着放,则下一个状态是now_s<<1|1
且对应i-1的状态是pre_s<<1 (上一行这个位置必为空才能放)
3.
一个位置不放,则下一个状态是now_s<<1
且对应i-1的状态是pre_s<<1|1 (上一行这个位置必不为空才能不放)
*/
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 12;
typedef long long llt;
llt dp[2][1<<N];
int n, m, now;


void dfs(int col, int now_s, int pre_s)
{
    if(col > m) return;
    if(col == m)
    {
        dp[now][now_s] += dp[!now][pre_s];
        return;
    }
    dfs(col + 1, now_s << 1, pre_s << 1 | 1);
    dfs(col + 1, now_s << 1 | 1, pre_s << 1);
    dfs(col + 2, now_s << 2 | 3, pre_s << 2 | 3);
}
int main()
{
    while(scanf("%d %d", &n, &m))
    {
        if(n == 0 && m == 0) break;
        if(n < m) swap(n, m);
        memset(dp, 0, sizeof(dp));
        dp[0][(1<<m)-1] = 1;//假设上一行一开始是全满的(第一次是虚拟的上一行)
        now = 1;
        for(int i = 0; i < n; i++)
        {
            dfs(0, 0, 0);
            memset(dp[!now], 0, sizeof(dp[!now]));
            now = !now;
        }
        printf("%lld\n", dp[!now][(1<<m)-1]);
    }
}