[状态压缩DP] PKU 2411 Mondriaan's Dream

参考http://wenku.baidu.com/view/e262a86f1eb91a37f1115c26.html

状态设计:0表示横放,1表示竖放,可以预处理出所有合法状态,f[i, s] 表示到达第 i 层的状态(类似俄罗斯方块,前 i 层合并之后剩余的状态)。

状态转移:f[i, s] = sum{f[i-1, s']},s' 为和 s 符合的状态 j 与 s 的异或值。

# include <cstdio>
# include <cstring>

# define N 11 + 1

typedef long long int LL;

int m, n;
LL f[N][1<<N];

bool check(int x)
{
    int tmp = 0;
    for (int i = 0; i < n; ++i)
    {
        if ((x>>i)&0x1) continue;
        else
        {
            while (i<n && (((~x)>>i)&0x1))
            {
                ++i;
                ++tmp;
            }
            if (tmp & 0x1) return false;
            else tmp = 0;
        }
    }
    //printf("%04X\n", x);
    return true;
}

LL dp(int i, int s)
{
        //printf(" : %d\n", i);
    LL &ans = f[i][s];
    if (ans != -1) return ans;
    ans = 0;
    for (int j = 0; j < (1<<n); ++j)
    {
        if ((j^s)==j-s && check(j)) ans += dp(i-1, j^s);
    }
    return ans;
}

void solve(void)
{
    memset(f[0], 0, sizeof(LL)*(1<<n));
    f[0][0] = 1;
    for (int i = 1; i <= m; ++i)
        memset(f[i], -1, sizeof(LL)*(1<<n));
    LL ans = dp(m, 0);                        // 0 ~ n-1
    printf("%lld\n", ans);
}

int main()
{
    while (scanf("%d%d", &m, &n), m||n)
        solve();

    return 0;
}
原文地址:https://www.cnblogs.com/JMDWQ/p/2624014.html