• 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;
    }
    

      

      

  • 相关阅读:
    Python-操作符与基本数据类型
    初识Python
    HDU 1166 敌兵布阵(线段树求sum)
    HDU 1754 I Hate It(线段树求max)
    HDU 1176 免费馅饼
    HDU 1466 计算直线的交点数
    HDU 1506 Largest Rectangle in a Histogram(最大矩形面积)
    AYOJ 单词接龙(搜索)
    AYOJ 传球游戏(递推)
    AYOJ 方格取数(多进程DP)
  • 原文地址:https://www.cnblogs.com/Apro/p/4912244.html
Copyright © 2020-2023  润新知