[ACM] HDU 1400 Mondriaan's Dream (状态压缩,长2宽1长方形铺满)

Mondriaan‘s Dream

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 783    Accepted Submission(s): 506

Problem 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 file 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

University of Ulm Local Contest
2000

解题思路:

如图:问铺满大举行一共同拥有多少种方法。

由于长宽最大11,能够状态压缩.

从第一行開始铺砖。

dp[ i ]  [ j ] 定义为 第i行的状态为 j 一共同拥有多少种方法 .

把小矩形用01状态表示,小矩形由两个正方形组成。 对于横着放的小矩形,左右两个正方形用11表示,对于竖着的小矩形,上下两个正方形用分别01表示。

第i行的状态s2与第i-1行的状态s1有关。

s1和s2满足两个条件:

1.   s1  |  s2  得到的数二进制每一位都是1 ,由于对于竖着放的 ,0|1肯定是1,横着放的都是11,相或也是11.

2.   s1  & s2  得到的数连续的1是偶数个,注意0也是偶数。这个看图观察就能够了。

本题犯的错误:

1.

获取一个数x二进制的第i位是0或者1。用 if( x&(1<<i) ==1) 是不正确的, 这句话的意思是,把x的二进制数除了第i位都设为0,第i位通过 &1,来推断是0或者1,可是得到的数不一定是1,是2的倍数,比方 0010  或者 0100.

2.

推断一个数x二进制的每一位是否等于1 ,如果有m位 , 直接用 if( x==1<<m)-1),不用每一位的推断。前者效率更高。

代码:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <string.h>
using namespace std;
#define ll long long
ll dp[12][1<<12];//dp[i][j]表示第i行状态为j有多少种方法
int n,m;

bool ok(int s1,int s2)
{
    int temp=s1|s2;//两个状态或运算每一位都必须是1
    if(temp!=(1<<m)-1)
        return false;
    int cnt=0;
    temp=s1&s2;//两个状态且运算,必须连续的1都是偶数个
    for(int i=0;i<m;i++)
    {
        if((temp&(1<<i)))//第i位是1
            cnt++;
        else
        {
            if(cnt&1)
                return false;
        }
    }
    if(cnt&1)
        return false;
    return true;
}

void solve()
{
    memset(dp,0,sizeof(dp));
    int maxd=1<<m;
    for(int i=0;i<maxd;i++)//铺第一行
        if(ok(maxd-1,i))
            dp[1][i]++;
    for(int i=2;i<=n;i++)//铺第i行
    {
        for(int j=0;j<maxd;j++)
        {
            for(int k=0;k<maxd;k++)
                if(ok(j,k))
                    dp[i][j]+=dp[i-1][k];
        }
    }
    ll ans=0;
    ans+=dp[n][maxd-1];//最后一行肯定都是1
    printf("%I64d\n",ans);
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(!n||!m)
            break;
        if(n*m&1)//小方块的个数为奇数个,肯定不能铺满
        {
            printf("0\n");
            continue;
        }
        if(n<m)
            n=n^m,m=n^m,n=n^m;
        solve();
    }
    return 0;
}

[ACM] HDU 1400 Mondriaan's Dream (状态压缩,长2宽1长方形铺满)

时间: 2024-10-09 10:53:29

[ACM] HDU 1400 Mondriaan&#39;s Dream (状态压缩,长2宽1长方形铺满)的相关文章

[ACM] HDU 1400 Mondriaan&#39;s Dream (状态压缩,长2宽1长方形铺满)

Mondriaan's Dream Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 783    Accepted Submission(s): 506 Problem Description Squares and rectangles fascinated the famous Dutch painter Piet Mondri

[ACM] HDU 5025 Saving Tang Monk (状态压缩,BFS)

Saving Tang Monk Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 941    Accepted Submission(s): 352 Problem Description <Journey to the West>(also <Monkey>) is one of the Four Great Clas

POJ 2411 &amp;&amp; HDU 1400 Mondriaan&#39;s Dream (状压dp 经典题)

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

HDU 1400 Mondriaan&#39;s Dream

状压DP. #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int h,w; long long dp[15][(2<<12)+10]; bool flag[(2<<12)+10],c[(2<<11)+10]; int b[15]; void dfs(int p){ if(p==w){ 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,

HDU 4640 Island and study-sister(状态压缩)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4640 题意:给出一个无向图,边有权值.三个人初始时呆在1号点.在其余n-1个点中有些点要求被遍历到.且除了1号点之外每个点最多只能被一个人遍历.求要求被遍历的点中最后被遍历的点的最小时刻. 思路:用f[st][i]表示一个人遍历完集合st最后停在i的最小时间,之后用f[st][i]得到f1[st],表示遍历完集合st的最小时间.然后得到dp[i][st]表示i个人遍历完st的最小时间. int g[

Mondriaan的梦(状态压缩dp)

题目原题可以看POJ2411,大意是给出m*n的矩形,要用2*1的矩形将它铺满(不能讲一个矩形铺在另外一个上面),求方案数,并且只要不是完全相同的就算不同的方案,也就是对称算不同的方案. F[i][s]表示前i-1行已经填满,并且第i行的状态是s的方案数. F[i][s]=sum(F[i-1][s’]): s‘能转移到s.如何根据s来确定s'呢.这里用一个dfs实现,一位一位去填充s'.扫描s,如果该位是1,那么s’对应的这位必定是0,如果该位是0,那么要分情况讨论: 如果该位的后面一位也是0,

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行刚好铺满.