POJ2411_Mondriaan's Dream_轮廓线dp

来源:互联网 发布:淘宝直通车定向推广 编辑:程序博客网 时间:2024/06/03 16:08

Mondriaan's Dream
Time Limit: 3000MS Memory Limit: 65536KTotal Submissions: 16640 Accepted: 9606

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 21 31 42 22 32 42 114 110 0

Sample Output

10123514451205

用 2 * 1 的骨牌铺满 w * h 的棋盘,有多少中铺法。


状态压缩的轮廓dp。

从第一个格开始,从左往右,从上往下对每个格进行dp。

转移的状态是已处理和未处理的交界线上的格子的状态。把前一个格子的决策导致的当前状态,转移到当前格子决策产生的下一个状态。

具体的说,如果前一个格子铺上后,当前格子是黑色的,则这个格子不能放骨牌,只能转移到同列的下一个格子是白色的状态。如果是白色的,则可以选择竖着放或者横着放。横着放就转移到 j + 1 个格子是黑色的状态(状态转移是横向移动的,如果恰好是行尾,则不能横放),竖着放则转移到同列下一个格子是黑色的状态。以此进行转移就好了。初始状态,也就是对第一个格子决策时面对的状态是,前一个格子(不存在)只转移了一种状态过来,就是所有格子都是白色,种数为1,dp[0][0] = 1。其他状态种数都是0。

最终状态,决策完最后一个格子后,转移到下一个轮廓线上所有个子都为白色,说明恰好平铺。这样的种数就是待求答案。


#include<cstdio>#include<iostream>#include<cstring>using namespace std;typedef long long LL;const int maxn = 12;int w, h;LL dp[2][1<<maxn];// cur 处理完前一个格后当前轮廓的状态// next 处理完当前格后下一个轮廓的状态 LL *cur = dp[0], *next = dp[1];int main(){while(1){scanf("%d %d", &h, &w);if(w == 0 && h == 0) break;if(w < h) swap(w, h);memset(dp, 0, sizeof dp);// -1格填满后,第0行只有状态0这一种情况,且种数为1 cur[0] = 1;for(int i= 0; i< h; i++)for(int j= 0; j< w; j++){// 初始化 memset(next, 0, sizeof(dp[0]));for(int s= 0; s< 1<<w; s++){// 当前状态下j格是黑的,它只能转移到j格是白色的情况 if(s>>j & 1) next[s & ~(1<<j)] += cur[s];// j格是白的// 骨牌竖着摆,转移到j格为黑else next[s | 1<<j] += cur[s];// 骨牌横着摆,转移到j+1格为黑 if(j < w-1 && !(s>>j & 3)) next[s | 1<<(j+1)] += cur[s];}swap(cur, next);if(i == h-1 && j == w-1)printf("%lld\n", cur[0]);}}return 0;}


原创粉丝点击