poj2411_Mondriaan's Dream_状压DP(插头)

题目大意
用 1 * 2 的骨牌密铺 h * w 的方格

思路
用k记录考虑第(i, j)时的复杂状态,k & (1 << (j - 1)) 为1时表示此时已被之前的操作所覆盖(来自 (i - 1, j) 或 (i, j - 1)),为0时未被覆盖

三维dp数组,一直超时,降维后AC

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define INF 0x3f3f3f3f
#define rep0(i, n) for (int i = 0; i < n; i++)
#define rep1(i, n) for (int i = 1; i <= n; i++)
#define rep_0(i, n) for (int i = n - 1; i >= 0; i--)
#define rep_1(i, n) for (int i = n; i > 0; i--)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define mem(x, y) memset(x, y, sizeof(x))
#define MAXH 15

using namespace std;
typedef long long LL;
int h, w;
LL dp[MAXH][1 << MAXH];
void DP()
{
    dp[0][0] = 1;
    for (int i = 1; i <= h; i++)
    {
        if (i > 1)
            for (int k = 0; k < (1 << w); k++)
                dp[0][k] = dp[w][k];


        for (int j = 1; j <= w; j++)
        {
            mem(dp[j], 0);
            int up = 1 << (j - 1), r = 1 << j;
            for (int k = 0; k < (1 << w); k++)
            {
                /**
                当(i, j)已被覆盖时,(i, j + 1)不会被覆盖
                当(i, j)被覆盖时,竖放后(i, j + 1)被覆盖
                */
                dp[j][k ^ up] += dp[j - 1][k];

                if ((k & up) == 0 && (k & r) == 0)
                {
                    //考虑横放
                    dp[j][k ^ r] += dp[j - 1][k];

                }



            }
        }
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif // ONLINE_JUDGE

    while (scanf("%d %d", &h, &w) != EOF && h && w)
    {
        mem(dp, 0);
        DP();
        printf("%lld\n", dp[w][0]);

    }


    return 0;
}

猜你喜欢

转载自blog.csdn.net/Anna__1997/article/details/79393031