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!
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 }