[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-08-03 23:39:00

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

[ACM] HDU 1400 Mondriaan&amp;#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

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,

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

hdu 4778 Gems Fight!(状态压缩+博弈+记忆化)

Gems Fight! Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) Total Submission(s): 1383    Accepted Submission(s): 587 Problem Description Alice and Bob are playing "Gems Fight!": There are Gems of G differe

Wireless Password - HDU 2825(ac自动机+状态压缩)

题目大意:有个人想破解他邻居的密码,他邻居告诉了一些关于这个密码的信息,并且给他一个单词集合,他用这些信息判断一下最少有多少种密码. 1->, 所有的密码都是有小写字母组成. 2->,密码的长度是 n (1<= n <=25). 3->,密码至少包含 k 种字符集里面的单词. 比如,给集合{"she", "he"},单词长度是3,最少包含两个单词的密码,很明显只能是“she”(题目表述的不清楚).   分析:因为要统计记录到达每个点时候

HDU 1074 Doing Homework (状态压缩DP)

Doing Homework Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3595    Accepted Submission(s): 1424 Problem Description Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lo