POJ 2411 Mondriaan's Dream(状态压缩+深搜)

每一行的填充仅与上一行有关系,每行的目的都是至少填充满上一行。

当填充到i行的时候,i-1行某列没填充必须用竖直的方格填充,这是固定的,剩下其余的则搜索填充。

用2进制的01表示不放还是放

第i行只和i-1行有关

枚举i-1行的每个状态,推出由此状态能达到的i行状态

如果i-1行的出发状态某处未放,必然要在i行放一个竖的方块,所以我对上一行状态按位取反之后的状态就是放置了竖方块的状态。

然后用搜索扫一道在i行放横着的方块的所有可能,并且把这些状态累加上i-1的出发状态的方法数,如果该方法数为0,直接continue。

举个例子

2 4

1111

1111

状态可以由

1100 0000 0110 0011 1111

0000 0000 0000 0000 0000

这五种i-1的状态达到,故2 4 的答案为5

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
int n,m;
ll add;
ll dp[2][1<<12];
void dfs(int i,int s,int cur)
{
   if(cur==m) {dp[i][s]+=add;return;}
   dfs(i,s,cur+1);
   if(cur<m-1 && !(s&(1<<cur)) && !(s&1<<(cur+1)) )
   dfs(i,s|(1<<cur)|1<<(cur+1),cur+2);
}
int main()
{
    while(scanf("%d%d",&n,&m),n+m)
    {
        if(n*m%2) {printf("0\n");continue;}
        int rt=(1<<m)-1;
        add=1;//这个起先没明白。这样考虑第一行填充的每种方法都是1种,唯一且与上行没关系
        memset(dp,0,sizeof(dp));
        dfs(0,0,0);
        for(int i=1;i<n;i++)
            for(int j=0;j<=rt;j++)if(dp[(i-1)%2][j])
                    add=dp[(i-1)%2][j],dfs(i%2,~j&rt,0);
        printf("%I64d\n",dp[(n-1)%2][rt]);
    }
    return 0;
}

POJ 2411 Mondriaan's Dream(状态压缩+深搜)

时间: 2024-10-12 20:22:55

POJ 2411 Mondriaan's Dream(状态压缩+深搜)的相关文章

[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(状态压缩+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 (状态压缩)

题目大意:要在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(转态压缩)

题目链接:poj 2411 Mondriaan's Dream 题目大意:用1?2的木块填满n?m的矩阵有多少种方法. 解题思路:插头dp裸题.uva11270 #include <cstdio> #include <cstring> typedef long long ll; const int N = 13; int n, m; ll set, dp[N+5][(1<<N)+5]; void solve (int d, int s, int pos) { if (p

POJ 2411 Mondriaan&#39;s Dream

题目链接:http://poj.org/problem?id=2411 状态压缩Dynamic Programming. For each row, at ith position, 1 means that there is a block placed at this row and next row (vertically). otherwise, its 0. For the example in question, the state of For the example in que

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)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

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

http://poj.org/problem?id=2411 求一个n*m矩阵用1*2方块去填满的情况有几种 思路:状压dp,先预处理那些状态之间能互相到达,情况就几种,上一个两个1,下一个状态也两个1,上一个为0,下一个必须为1,还有一种是上一个为1,下一个为0的情况 然后就一层层往后递推即可 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int

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