poj 2411 Mondriaan'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】)

即所有的当前行都是由上一行合法的状态转移而来。

而状态的合法性由两种铺法得到,第一种横放,注意要求前一行全满,然后竖放,上一行为空,可以留空。

AC代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const long long N = 15;
long long dp[N][1<<N];
long long ans[N][N];
long long n,m;
bool solve(long long st)
{
    long long tmp=0;
    for(long long i=0; i<m; i++)
    {
        if(st&(1<<i))
            tmp++;
        else
        {
            if(tmp%2)
                return false;
            tmp=0;
        }
    }
    if(tmp%2)
        return false;
    return true;
}
bool cmp(long long st,long long up)
{
    for(long long i=0; i<m; i++)
    {
        if(st&(1<<i))
        {
            if(up&(1<<i))
            {
                if(i==m-1 || !(st&(1<<(i+1))) || !(up&(1<<(i+1))))
                    return false;
                else
                    i++;
            }//否则的话竖放
        }
        else
        {
            if(!(up&(1<<i)))
                return false;
        }
    }
    return true;
}
int main()
{
    memset(ans,0,sizeof(ans));
    while(~scanf("%lld%lld",&n,&m))
    {
        if(n==0 && m==0)
            break;
        if((m*n)%2)
        {
            printf("0\n");
            continue;
        }
        if(m>n)
            swap(m,n);
        if(ans[n][m])
        {
            printf("%lld\n",ans[n][m]);
            continue;
        }
        memset(dp,0,sizeof(dp));
        long long len = 1<<m;
        for(long long i=0; i<len; i++)
        {
            if(solve(i))
                dp[1][i]=1;
        }
        for(long long i=2; i<=n; i++)
        {
            for(long long st=0; st<len; st++) //当前行
            {
                for(long long k = 0; k<len; k++) //上一行
                {
                    if(cmp(st,k))
                        dp[i][st]+=dp[i-1][k];
                }
            }
        }
        printf("%lld\n",dp[n][len-1]);
        ans[n][m] = dp[n][len-1];
    }
    return 0;
}

poj 2411 Mondriaan's Dream 【dp】

时间: 2024-08-14 09:07:28

poj 2411 Mondriaan's Dream 【dp】的相关文章

POJ 2411 Mondriaan&#39;s Dream( 轮廓线dp )

最普通的轮廓线dp... 复杂度O(nm2min(n, m)) -------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; #define b(x) (1 << (x)) const in

POJ 3411 Mondriaan&#39;s Dream 【状压Dp】 By cellur925

Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series' (where he had to use his toilet paper to draw on, for all of his paper was filled with squares and rectangles),

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(状压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)

 题意:用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)

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入门

题意: 求h*w的矩形被1*2的小矩形覆盖的方案数. 分析: 状压dp入门,<挑战程序设计竞赛>上讲的很好,好几天才看懂. 代码: #include <iostream> using namespace std; __int64 ans[16][16]; int n,m; __int64 dp[2][1<<16]; __int64 solve() { int i,j,used; memset(dp,0,sizeof(dp)); __int64 *crt=dp[0],*n

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 状态压缩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