POJ2411 Mondriaan's Dream

Mondriaan's Dream
Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 17769   Accepted: 10198

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

 
【题解】
状压DP常规思路:预处理所有合法状态
由于对当前行防止方案有影响的为当前行的上一行,所以我们要确定当前行状态为s1时,
上一行的合法状态s2
dfs预处理,now表示当前行,pre表示上一行
0表示 不放
1表示 横放 或者 竖放的下一格
对于位置d,有三种决策:
1、横放,pre相同的位置必须为1,否则无法被填充,不合法
2、竖放,pre相同位置必须为0,否则放不下
3、不放,pre相同位置必须为1,要不你那什么填充那个位置?
然后转移即可。dp[i][j]表示第i行为状态j的方案数。
初始:虚拟一行0,全为1,表示第一行只能横放或者不放
采用刷表法,状压DP刷表法很好用
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cmath> 
 6 #include <algorithm>
 7 #define min(a, b) ((a) < (b) ? (a) : (b))
 8 #define max(a, b) ((a) > (b) ? (a) : (b))
 9  
10 inline void read(long long &x)
11 {
12     x = 0;char ch = getchar(), c = ch;
13     while(ch < '0' || ch > '9')c = ch, ch = getchar();
14     while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
15     if(c == '-')x = -x;
16 }
17 
18 const long long INF = 0x3f3f3f3f; 
19 const long long MAXW = 15;
20 const long long MAXH = 15;
21 
22 long long status[1 << MAXH][2], w, h, tot, dp[MAXW][1 << MAXH];//[0]代表pre,[1]代表now
23 
24 /*
25 状态定义:
26 0:不放 或者 竖着的上面一格
27 1:横着的 或者 竖着的下面一格 
28 */
29 
30 void dfs(long long pre, long long now, long long d)
31 {
32     if(d > h)return;
33     if(d == h)
34     {
35         status[++tot][0] = pre;
36         status[tot][1] = now;
37         return;
38     }
39     dfs((pre << 2) | 3, (now << 2) | 3, d + 2);
40     dfs(pre << 1, (now << 1) | 1, d + 1);
41     dfs((pre << 1) | 1, now << 1, d + 1);
42 } 
43 
44 int main()
45 {
46     read(w), read(h);
47     while(w + h)
48     {
49         tot = 0;
50         dfs(0,0,0);
51         memset(dp, 0, sizeof(dp));
52         dp[0][(1 << h) - 1] = 1;
53         for(register long long i = 0;i < w;++ i)
54         {
55             for(register long long j = 1;j <= tot;++ j)
56                 dp[i + 1][status[j][1]] += dp[i][status[j][0]];
57         }
58         printf("%lld\n", dp[w][(1 << h) - 1]); 
59         read(w), read(h);
60     }
61     return 0;
62 }
POJ2411

 

posted @ 2017-09-11 15:03  嘒彼小星  阅读(168)  评论(0编辑  收藏  举报