poj 2411 Mondriaan's Dream

题目链接 http://poj.org/problem?id=2411

Mondriaan's Dream
Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 12445   Accepted: 7261

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

题意:给你一块h*w的矩形,要用1*2的小矩形块铺满它,可以竖着放,也可以横着放。问最多有多少种情况。
参考:http://www.cnblogs.com/jackge/archive/2013/05/24/3097205.html
分析:因为要铺满,可以知道如果给出的h*w如果为奇数的时候,肯定铺不满,如1 3。
如果是偶数的情况。
设dp[i][j]为第i行,状态为j时候的最多方法数。
因为最后都要铺满。
考虑某一行的第k列的这一格,有三种情况。
1.是横放的第一个,那么第k+1列的那一格就是横放的第二格子,所以把这两个位置设为1 1.
2.竖放,和上一行的这一列的那一格子组成一块。那么设这个位置为1,上一行的对应位置为0.
3.竖放,和下一行的这一列的那一个格子组成一块。那么设这个位置0,上一行的对应位置为1.
在这样设的情况下,各种情况不会冲突。
而第一行需要特殊考虑,因为第一行之前没有上一行,所以如果要竖放只有一种情况。
参考了别人的代码,是用dfs写的,很简洁,学习了。
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <string>
 5 #include <algorithm>
 6 using namespace std;
 7 int h, w;
 8 long long dp[12][(1<<12)+1];
 9 void init(int sta, int pos){
10     if(pos == w){
11         dp[1][sta] = 1;
12         return;
13     }
14     if(pos + 1 <= w){  //可以竖放,而且如果竖放,这里必须为0,因为第一行并没有上一行。 
15         init(sta<<1, pos+1);
16     }
17     if(pos + 2 <= w){  //可以横着放 
18         init(sta<<2|3, pos+2);
19     }
20 }
21 void dfs(int i, int nows, int pres, int pos){
22     if(pos == w){
23         dp[i][nows] += dp[i-1][pres]; 
24         return;
25     }
26     if(pos + 1 <= w){//竖着放 
27         dfs(i, nows<<1|1, pres<<1, pos+1); //这一行和上一行成一个竖块。
28         dfs(i, nows<<1, pres<<1|1, pos+1); //这一行和下一行成一个竖块。 
29     } 
30     if(pos + 2 <= w){
31         dfs(i, nows<<2|3, pres<<2|3, pos+2);
32     } 
33 }
34 int main(){
35     while(scanf("%d%d", &h, &w) &&(h+w)){
36         if((h*w)%2){
37             printf("0\n");
38             continue;
39         }
40         memset(dp, 0, sizeof(dp));
41         init(0, 0);
42         for(int i = 2; i <= h; i++) dfs(i, 0, 0, 0);
43         cout<<dp[h][(1<<w)-1]<<endl;
44     }
45     
46     return 0;
47 }

 

posted @ 2015-03-21 19:36  下周LGD该赢了吧  阅读(130)  评论(0编辑  收藏  举报