描述
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!输入
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.
输出
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.
样例
- Input
1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0- Output
1
0
1
2
3
5
144
51205
题解
- 题意很简单,就是一个nm的矩阵,要求用1 2的方格来填满它,问有多少种填法
- 对于每一个位置,我们有三种放置方法——不放,横着放,竖着放。横着放的时候,我们用11表示;竖着放的时候;我们让方格上方为0,下方为1;不放的时候我们用0表示,注意如果位置i不放的话,上一行的i位置不能是0,下一行的i位置必须是1,这样刚好也能满足上0下1的竖放方式
- 用now表示当前行,用pre表示上一行,初始值均为0.那么对应三种状态就有三种表示方式:
不放:now<<1,pre<<1|1
竖放:now<<1|1,pre<<1
横放:now<<2|3,pre<<2|3- 用dp[i][sta]来表示当前行为i,状态为sta的情况下的种数和,那么dp[h-1][(1<<w)-1]就是最终答案。我们用p,now表示当前行数和当前行的某状态,用q,pre表示上一行数和上一行的某状态,那么当这一行从0开始填到n的时候,dp[p][now]+=dp[q][pre]。
- 我们采用dfs的方式对这一行和上一行同时进行填写,若当前填好的各种数为n,则:
当n+1<=w:当n+2<=w:dfs(n+1,now<<1,pre<<1|1);//这一行不放上一行放 dfs(n+1,now<<1|1,pre<<1);//上一行之前没放,这一行竖放当n==w:dfs(n+2,now<<2|3,pre<<2|3);//上一行和这一行都竖着放dp[p][now]+=dp[q][pre];return ;Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using namespace std;
const int MAX=0x7fffffff;
const int MIN=-0x7fffffff;
const int INF=0x3f3f3f3f;
const int Mod=1e9+7;
const int MaxN=1e7+7;
int w,h,p,q; //p,q控制滚动数组
LL dp[2][1<<12]; //这里采用滚动数组,所以只开两个
void dfs(int n,int now,int pre){
if(n==w){
dp[p][now]+=dp[q][pre];
return ;
}
if(n+1<=w) {
dfs(n+1,now<<1,pre<<1|1);//这一行不放上一行放
dfs(n+1,now<<1|1,pre<<1);//上一行之前没放,这一行竖放
}
if(n+2<=w)
dfs(n+2,now<<2|3,pre<<2|3);//上一行和这一行都竖着放
}
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
while(~scanf("%d%d",&w,&h)&&(w||h)){
if((w*h)%2==1){
printf("0\n");
continue;
}
INIT(dp,0);
dp[0][(1<<w)-1]=1,p=q=0;
for(int i=0;i<h;i++){
p=q^1; //p表示当前行,q表示上一行,然后不断轮换
dfs(0,0,0); //每一行从0开始填
INIT(dp[q],0);
q=p; //轮换
}
printf("%lld\n",dp[p][(1<<w)-1]);
}
return 0;
}两发状压直接弄自闭,好菜啊/fad(小声bb…)