poj 2411 Mondriaan's Dream 骨牌铺放 状压dp

题目链接

题意

用\(1\times 2\)的骨牌铺满\(H\times W(H,W\leq 11)\)的网格,问方案数。

思路

参考focus_best.

竖着的骨牌用\(\begin{pmatrix}0\\1\end{pmatrix}\)表示,横着的骨牌用\(\begin{pmatrix}1&1\end{pmatrix}\)表示。

则对于第\(i\)行,与之相容的第\(i-1\)行的状态需满足:

  1. 第\(i\)行是0的位置,第\(i-1\)行必须是1;
  2. 第\(i\)行是1的位置,第\(i-1\)行可为1可为0;如果是1则需满足,这样的连续的1的个数必为偶数(因为为横放)。

此外,
最后一行必为全1状态,
第一行需满足可以作为第一行的条件:这等价于,第一行的上一行可以表示为全1状态。

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 13
#define maxs 2100
using namespace std;
typedef long long LL;
int h, w; LL dp[maxs][maxn];
bool vis[maxs][maxn], hori[maxn];
bool check(int s1, int s2) {
    memset(hori, 0, sizeof hori);
    F(i, 0, w) {
        if (!(s2&(1<<i))) {
            if (!(s1&(1<<i))) return false;
        }
        else {
            if (s1&(1<<i)) hori[i] = true;
        }
    }
    int cont = 0; bool flag = false;
    F(i, 0, w+1) {
        if (!hori[i]) {
            if (cont&1) return false;
            cont = 0;
        }
        else ++cont;
    }
    return true;
}
LL dfs(int state, int row) {
    if (!row) {
        if (state==(1<<w)-1) return 1;
        else return 0;
    }
    if (vis[state][row]) return dp[state][row];
    vis[state][row] = true;
    LL temp=0;
    F(i, 0, 1<<w) {
        if (check(i, state)) temp += dfs(i, row-1);
    }
    return dp[state][row] = temp;
}
void work() {
    memset(vis, 0, sizeof vis);
    memset(dp, 0, sizeof dp);
    if (h<w) swap(h,w);
    printf("%lld\n", dfs((1<<w)-1, h));
}
int main() {
    while (scanf("%d%d", &h, &w) != EOF && h && w) work();
    return 0;
}

poj 2411 Mondriaan's Dream 骨牌铺放 状压dp

原文地址:https://www.cnblogs.com/kkkkahlua/p/8452967.html

时间: 2024-10-09 12:33:34

poj 2411 Mondriaan's Dream 骨牌铺放 状压dp的相关文章

poj 2411 Mondriaan&#39;s Dream(状态压缩+dp)

 题意:用1*2砖块铺满n*m的房间. 思路转自:http://www.cnblogs.com/scau20110726/archive/2013/03/14/2960448.html 因为这道题输入范围在11*11之间,所以可以先打表直接输出.......... 状态压缩DP 经典覆盖问题,输入n和m表示一个n*m的矩形,用1*2的方块进行覆盖,不能重叠,不能越出矩形边界,问完全覆盖完整个矩形有多少种不同的方案 其中n和m均为奇数的话,矩形面积就是奇数,可知是不可能完全覆盖的.接着我们来看

POJ 2411 Mondriaan&#39;s Dream ——状压DP 插头DP

[题目分析] 用1*2的牌铺满n*m的格子. 刚开始用到动规想写一个n*m*2^m,写了半天才知道会有重复的情况. So Sad. 然后想到数据范围这么小,爆搜好了.于是把每一种状态对应的转移都搜了出来. 加了点优(gou)化(pi),然后poj上1244ms垫底. 大概的方法就是考虑每一层横着放的情况,剩下的必须竖起来的情况到下一层取反即可. 然后看了 <插头DP-从入门到跳楼> 这篇博客,怒抄插头DP 然后16ms了,自己慢慢YY了一下,写出了风(gou)流(pi)倜(bu)傥(tong)

POJ - 2411 Mondriaan&#39;s Dream (状态压缩)

题目大意:要在n * m的网格上面铺满1 * 2或者 2 * 1的砖块,问有多少种铺放的方式 解题思路:刚开始用了3进制表示每行的状态,0表示的是2 * 1的砖块的一部分,1表示的是1 * 2的砖块的上部分,2表示的是1 * 2的砖块的下部分,然后像poj-1185炮兵阵地 那题一样去解决就好了,结果发现状态太多了,会TLE,只得放弃了 后面参考了下别人的代码,可以将其转换成二进制表示形式的,0代表没该位置没被铺到,1代表该位置有被铺到 因为有1 * 2的这种影响两行的砖头存在,所以要判断两个状

poj 2411 Mondriaan&#39;s Dream (轮廓线DP)

题意:有一个n*m的棋盘,要求用1*2的骨牌来覆盖满它,有多少种方案?(n<12,m<12) 思路: 由于n和m都比较小,可以用轮廓线,就是维护最后边所需要的几个状态,然后进行DP.这里需要维护的状态数就是min(n,m).即大概是一行的大小.每次放的时候,只考虑(1)以当前格子为右方,进行横放:(2)以当前格子为下方进行竖放:(3)还有就是可以不放. 3种都是不一样的,所以前面的一种状态可能可以转为后面的几种状态,只要满足了条件.条件是,横放时,当前格子不能是最左边的:竖放时,当前格子不能是

poj 2411 Mondriaan&#39;s Dream 【dp】

题目:poj 2411 Mondriaan's Dream 题意:给出一个n*m的矩阵,让你用1*2的矩阵铺满,然后问你最多由多少种不同的方案. 分析:这是一个比较经典的题目,网上各种牛B写法一大堆.题解也是 我们可以定义状态:dp[i][st]:在第 i 行状态为 st 的时候的最大方案数. 然后转移方程:dp[i][st] = sum (dp[i-1][ss]) 即所有的当前行都是由上一行合法的状态转移而来. 而状态的合法性由两种铺法得到,第一种横放,注意要求前一行全满,然后竖放,上一行为空

POJ 2411 Mondriaan&#39;s Dream (状压DP)

题意:给出一个n*m的棋盘,及一个小的矩形1*2,问用这个小的矩形将这个大的棋盘覆盖有多少种方法. 析:对第(i,j)位置,要么不放,要么竖着放,要么横着放,如果竖着放,我们记第 (i,j)位置为0,(i+1,j)为1,如果横着放,那么我们记 (i,j),(i,j+1)都为1,然后dp[i][s]表示 第 i 行状态为 s 时,有多少方法,那么我们就可以考虑与和匹配的状态,这个也很容易判断. 代码如下: #pragma comment(linker, "/STACK:1024000000,102

POJ 2411.Mondriaan&#39;s Dream 解题报告

题意: 给出n*m (1≤n.m≤11)的方格棋盘,用1*2的长方形骨牌不重叠地覆盖这个棋盘,求覆盖满的方案数. Solution:                位运算+状态压缩+dp                二进制数(####)代表填完一行后这一行的状态,填满的地方为1,未填的地方为0.                显然在填第i行时,能改变的仅为第i-1行和第i行,因此要满足在填第i行时,第1~i-2行已经全部填满.                DFS一行的状态,要是填完第i行时,

[POJ 2411] Mondriaan&#39;s Dream 状态压缩DP

题意 给定一个 n * m 的矩形. 问有多少种多米诺骨牌覆盖. n, m <= 11 . 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 6 #define LL long long 7 inline

POJ 2411 Mondriaan&#39;s Dream(状态压缩+深搜)

每一行的填充仅与上一行有关系,每行的目的都是至少填充满上一行. 当填充到i行的时候,i-1行某列没填充必须用竖直的方格填充,这是固定的,剩下其余的则搜索填充. 用2进制的01表示不放还是放 第i行只和i-1行有关 枚举i-1行的每个状态,推出由此状态能达到的i行状态 如果i-1行的出发状态某处未放,必然要在i行放一个竖的方块,所以我对上一行状态按位取反之后的状态就是放置了竖方块的状态. 然后用搜索扫一道在i行放横着的方块的所有可能,并且把这些状态累加上i-1的出发状态的方法数,如果该方法数为0,