POJ2411 Mondriaan's Dream(状态压缩)

Mondriaan‘s Dream

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 15295   Accepted: 8820

Description

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), he dreamt of filling a large rectangle with small rectangles of width 2 and height 1 in varying ways.

Expert as he was in this material, he saw at a glance that he‘ll need a computer to calculate the number of ways to fill the large rectangle whose dimensions were integer values, as well. Help him, so that his dream won‘t turn into a nightmare!

Input

The input contains several test cases. Each test case is made up of two integer numbers: the height h and the width w of the large rectangle. Input is terminated by h=w=0. Otherwise, 1<=h,w<=11.

Output

For each test case, output the number of different ways the given rectangle can be filled with small rectangles of size 2 times 1. Assume the given large rectangle is oriented, i.e. count symmetrical tilings multiple times.

Sample Input

1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0

Sample Output

1
0
1
2
3
5
144
51205

Source

Ulm Local 2000

/*
    已经给了时间看题解了,正式练习一道题三天之内不准再看题解!
*/
#include <iostream>
#include <stdio.h>
#include <string.h>
#define N (1<<12)+5
#define M 12
/*
用1表示当前小方格填满了,0表示没填满,初始化第一行的状态然后递推到最后一行
*/
using namespace std;
long long dp[M][N];//dp[i][j]表示第i行j种状态做多有多少种排列方式
int n,m;
bool check(int x)//判断是不是有连续个奇数个1;当有连续奇数个1的时候那么这一行横着放的肯定是不会填满的
{
    int s=0;
    while(x)
    {
        if(x&1)s++;
        else
        {
            if(s&1)return false;
            s=0;
        }
        x>>=1;
    }
    if(s&1)return false;
    return true;
}
int main()
{
    ///for(int i=0;i<30;i++)
    //    cout<<"i="<<i<<" "<<check(i)<<endl;
    //cout<<endl;
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(scanf("%d%d",&n,&m)!=EOF&&n&&m)
    {
        if((n*m)%2)//如果乘积是奇数的话是肯定铺不满的
        {
            printf("0\n");
            continue;
        }
        if(n<m)//这里做一个剪枝,使m永远是小的那个,能减少不少循环的次数
        {
            int tmp=n;
            n=m;
            m=tmp;
        }
        int tol=(1<<m);
        memset(dp,0,sizeof dp);
        for(int i=0;i<tol;i++)//初始第一行的状态
            if(check(i))
                dp[1][i]=1;
        for(int i=1;i<n;i++)//由i行推出i+1行
            for(int j=0;j<tol;j++)//枚举上一个状态
                if(dp[i][j]!=0)//上一个状态为零没计算意义
                {
                    for(int k=0;k<tol;k++)
                    {
                        if( (j|k)==tol-1 && check(j&k) )//这一步很精妙,(j|k)==tol-1保证了肯定能填满上一行,check(j&k)保证了这一行中横着放的小木块绝对能填满
                            dp[i+1][k]+=dp[i][j];
                    }
                }
        printf("%lld\n",dp[n][tol-1]);
    }
    return 0;
}

POJ2411 Mondriaan's Dream(状态压缩)

时间: 2024-08-06 07:51:32

POJ2411 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(状态压缩+深搜)

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

POJ2411(Mondriaan&#39;s Dream)

题目链接:传送门 题目大意:用1*2大小的砖块去铺满n*m大小的地面,有多少种方案 题目思路:因为1<=n,m<=11,并且砖块是1*2,故可以用二进制思想,也就是状态压缩DP,其中矩阵中为0的元素表示当前位置竖着放一块砖,而连着 两个1表示横着放一块砖(状态压缩真的很奇妙) #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <

poj2411 Mondriaan&#39;s Dream【状压DP】

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

pojPOJ 2411--Mondriaan&#39;s Dream+状态压缩dp

又是一道经典的状态压缩dp 开始自己想了一下,总是觉得因为这个小矩形可以竖着放导致没法确定状态如何转移(第i行的小矩形如果竖着放,及可能影响i-1行,也有可能影响i+1行);后面看了别人的题解后,才知道原来我们可以固定小矩形竖着放的时候只能向前放,这样第i行的状态就只能影响i-1行了,也就能顺利的写出状态转移方程啦. 设dp[i][j]表示第i行处于状态j的时候,共有多少种放置方法. dp[i][j]=sum(dp[i-1][k]),其中状态j和k要能共存,并且j和k要使得第i-1行刚好铺满.

状态压缩动态规划总结

状态压缩是一个很广的概念,在OI中也有很多的应用,当我们把他应用到动态规划中,可以用来精简状态,节约空间,也方便转移.最常见的就是用二进制来表是状态,利用各种位移运算,就可以实现\(O(1)\)的转移.状压DP适用于“窄棋盘”上的DP,否则状态太多无法存下. POJ1185 炮兵阵地 题意:给一个\(N \times M\)的地形盘,有平原和山坡,要求在平原上部署尽量多的炮(攻击范围2),使得不互相攻击. 数据范围:N <= 100:M <= 10,符合条件.如何表示状态?按行DP,一个二进制

POJ2411——状态压缩+DFS——Mondriaan&#39;s Dream

Description 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 r

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均为奇数的话,矩形面积就是奇数,可知是不可能完全覆盖的.接着我们来看

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

题目大意:有一些1*2的矩形,现在用这些小矩形覆盖M*N的大矩形,不能重复覆盖,并且要覆盖完全,求有多少种覆盖方式. 分析:可以使用1和0两种状态来表示这个位置有没有放置,1表示放置,0表示没有放置,可以有三种放置方式. 一,竖着放. 二,不放.三,横着放.直接DFS这些情况就行了................还是递归容易理解. 代码如下: =============================================================================