[状态压缩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;

}

你可能感兴趣的:(pku)