POJ 2411 Mondriaan's Dream(状压DP)

来源:互联网 发布:手机怎么连接电脑网络 编辑:程序博客网 时间:2024/06/05 16:59

Mondriaan’s Dream

Time Limit: 3000MSMemory Limit: 65536KTotal Submissions: 17936Accepted: 10285

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


[Submit]  
[Go Back]   [Status]  
[Discuss]

题意

    给你一个大小为hw的方格,让你用12的多米诺骨牌将该棋盘覆盖满,求方案数。

思路

    这题由于h,w的范围非常小,所以我们可以很轻易地想到状压DP。
    P.S. 本题题解参考http://blog.csdn.net/xingyeyongheng/article/details/21692655
    对于第k行第j列,有3种情况将该点铺满

由第k-1行第j列砖竖着铺将第k行第j列铺满
由第k行第j列被横铺砖铺满
第k行第j列砖竖着铺将该点铺满

    所以对于每一列的情况其实有两种(1,0)表示该点铺砖还是不铺
    而对于每一列必须到达的状态只有一种,就是被铺满(1)
    但是由上述3种情况将铺满方式分成两种:
    0和1表示被k-1行j列竖铺铺满和在k-1行被横铺铺满
    对于每一行列举每一种到达的状态j,dp[j]表示到达该状态有多少种情况
    分析对于第k-1行状态j:10000111
    需要到达第k行状态i: 01111011
    如果需要到达第k行j列状态是0,则必须第k-1行该点状态不能是0,否则一定是连续两列竖放冲突
    所以到达第k-1行该点只能是1,也就是说i|j一定每一位是1,也可以一步步判断是否满足第k行j列是0第k-1行j列是1
    如果需要到达第k行状态j列是1,则假如第k-1行该点是0,则该点状态可以到达,继续判断j+1列
    假如第k-1行该点是1,则第k行j列的1一定是横铺到达的,所以k行第j+1列一定也被铺满为1
    从而第k-1行j+1列一定不能竖铺,必须被横铺铺满,所以也是1.
    于是综合的第k行j列和第k-1行j列的关系(每一行每一列都表示到达的状态)

1:下面这种情况从第j列继续去判断j+1列
 1
 0
2:下面这种情况从第j列继续去判断j+1列
 0
 1
3:下面这种情况从第j列判断第j+1列是否全是1,然后继续判断第j+2列
 1
 1

Code

#pragma GCC optimize(3)#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>#include<cctype>#include<climits>#include<cstdlib>#include<cmath>#include<queue>#include<stack>#include<climits>#include<vector>using namespace std;typedef long long ll;inline void readInt(int &x) {    x=0;int f=1;char ch=getchar();    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();    x*=f;}inline void readLong(ll &x) {    x=0;int f=1;char ch=getchar();    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();    x*=f;}/*================Header Template==============*/const int maxn=(1<<11);ll f[2][maxn];int maxstatus[12],n,m;bool mark[maxn];inline void init(){maxstatus[0]=1;for(int i=1;i<=11;i++)maxstatus[i]=maxstatus[i-1]*2;}inline bool check(int statu) {    while(statu) {        if(statu&1) {            statu>>=1;            if(!(statu&1))                return 0;            statu>>=1;        }        else            statu>>=1;    }    return 1;}int main() {    init();    while(scanf("%d%d",&n,&m)==2&&n&&m) {        memset(f,0,sizeof f);        memset(mark,0,sizeof mark);        if((!n)||(!m)||((n*m)&1)) {            puts("0");            continue;        }        if(n<m)            swap(n,m);        for(int sta=0;sta<maxstatus[m];sta++)            if(check(sta)) {                f[0][sta]=1;                mark[sta]=1;            }        int now=0;        for(int i=2;i<=n;i++) {            now^=1;            for(int sta=0;sta<maxstatus[m];sta++)                f[now][sta]=0;            for(int sta=0;sta<maxstatus[m];sta++) {                for(int pre=0;pre<maxstatus[m];pre++) {                    if((sta|pre)!=maxstatus[m]-1||(!mark[sta&pre]))                        continue;                    f[now][sta]+=f[now^1][pre];                }            }        }        printf("%lld\n",f[now][maxstatus[m]-1]);    }    return 0;}
原创粉丝点击