zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

      

  • 相关阅读:
    虚函数和纯虚函数
    MS CRM 2011中PartyList类型字段的实例化
    MS CRM 2011的自定义与开发(12)——表单脚本扩展开发(4)
    MS CRM 2011的自定义与开发(12)——表单脚本扩展开发(2)
    MS CRM 2011的自定义和开发(10)——CRM web服务介绍(第二部分)——IOrganizationService(二)
    MS CRM 2011 SDK 5.08已经发布
    MS CRM 2011 Q2的一些更新
    最近很忙
    Microsoft Dynamics CRM 2011最近的一些更新
    补一篇,Update Rollup 12 终于发布了
  • 原文地址:https://www.cnblogs.com/Apro/p/4912244.html
Copyright © 2011-2022 走看看