POJ 2241 Mondriaan's Dream

题意:给一块n×m的空地,用1×2的砖铺,有多少种方案。

 

解法:状压dp。考虑dp[i][j]表示前i - 1行都铺满时第i行的状态为j时的方案数。对于第i行,每个格子上是否有砖用0和1表示,0表示不铺砖,1表示铺砖,二进制压缩状态,枚举第i - 1行的状态j和第i行的状态k,看这两种状态是否符合实际,如果符合实际,dp[i][k] += dp[i - 1][j]。因为在看第i行时要求i - 1行都铺满,所以j状态中0的位置k都必须是1,表示放一块2×1的砖,剩下的部分如果k的位置是1,则是放了1×2的砖,所以每段1的长度必须是偶数。

我貌似判是否符合实际的地方写屎了……总之没T就好哈哈哈哈哈哈哈

还有两个剪枝是n×m如果是奇数则答案是0,因为一块砖的面积是2,另一个剪枝是选择n和m中小的作为列数,可以让状态小一些,另外将答案打表也可以减少时间,我本来想把状态之间是否符合实际也打表……后来意识到这样是错的。

还有就是int会爆……orz

 

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<time.h>
#include<stdlib.h>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include<iomanip>
#define LL long long
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1

using namespace std;

int n, m;
LL ans[15][15];
LL dp[15][2050];
bool judge(int x, int y)
{
    int vis[20] = {0};
    for(int i = 0; i < m; i++)
    {
        if((x & (1 << i)) == 0)
        {
            vis[i] = 1;
            if((y & (1 << i)) == 0) return false;
        }
    }
    for(int i = 0; i < m - 1; i++)
    {
        if(vis[i] && (y & (1 << i))) continue;
        if(vis[i] && !(y & (1 << i))) return false;
        if(!vis[i] && (y & (1 << i)))
        {
            if(vis[i + 1]) return false;
            vis[i] = 1;
            vis[i + 1] = 1;
        }
    }
    if(vis[m - 1] && !(y & (1 << (m - 1)))) return false;
    if(!vis[m - 1] && (y & (1 << (m - 1)))) return false;
    return true;
}
LL solve()
{
    memset(dp, 0, sizeof dp);
    dp[0][(1 << m) - 1] = 1;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 0; j < (1 << m); j++)
        {
            for(int k = 0; k < (1 << m); k++)
            {
                if(judge(j, k)) dp[i][k] += dp[i - 1][j];
            }
        }
    }
    return dp[n][(1 << m) - 1];
}
int main()
{
    while(~scanf("%d%d", &n, &m) && !(n == 0 && m == 0))
    {
        if((n * m) & 1)
        {
            puts("0");
            continue;
        }
        if(m > n) swap(n, m);
        if(ans[n][m])
        {
            cout << ans[n][m] << endl;
            continue;
        }
        ans[n][m] = solve();
        cout << ans[n][m] << endl;
    }
    return 0;
}

  

  

posted @ 2015-10-26 20:09  露儿大人  阅读(186)  评论(0编辑  收藏  举报