您的位置:首页 > 其它

POJ 2411 Mondriaan's Dream(状压DP)

2017-10-13 17:50 351 查看

Mondriaan’s Dream

Time Limit: 3000MSMemory Limit: 65536K
Total 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!InputThe 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 Input1 2

1 3

1 4

2 2

2 3

2 4

2 11

4 11

0 0

Sample Output1

0

1

2

3

5

144

51205

SourceUlm Local 2000

[Submit]

[Go Back] [Status]

[Discuss]

题意

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

思路

这题由于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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj dp