标签:
题目链接 http://poj.org/problem?id=2411
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 12445 | Accepted: 7261 |
Description
Input
Output
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 }
标签:
原文地址:http://www.cnblogs.com/titicia/p/4356061.html