POJ 2411 - Mondriaan\'s Dream

来源:互联网 发布:金山数据恢复账号2017 编辑:程序博客网 时间:2024/06/06 09:07
Mondriaan's Dream
Time Limit: 3000MSMemory Limit: 65536KTotal Submissions: 15272Accepted: 8806

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. 
POJ 2411 - Mondriaans Dream - 卢凯宾 - 石门实验中学卢凯宾的博客

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

POJ 2411 - Mondriaans Dream - 卢凯宾 - 石门实验中学卢凯宾的博客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

Source

Ulm Local 2000   
对于一个n*m的矩形,希望用1*2的矩形填满,不能重叠,问有多少种填充方式,有多组测试数据。

这题也是状压dp,状态压缩方式与之前做的那题大致相同,判断略微复杂。

显然,对于第i行第j列,如果i-1行j列没有被填,那么必定要竖填一个(不然无法填满);否则,则可以横填或不填。

但是由上一行考虑本行有点麻烦,所以lkb比较喜欢由这一行推到下一行的方式。

在找出可行的状态的时候可以不用嵌套循环的枚举而改用dfs,会好些。

#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 11 + 5;
const int maxm = 11 + 5;

int n, m;

//保存在当前状态下,下一行的可能状态
int cnt = 0;
int state[1 << maxm];

//状压dp数组
long long f[maxn][1 << maxm];

void dfs(int k, int p) {
//深搜找出所有可能的状态
//当前状态为k(二进制)
//p为二进制"指针"
if(p + 1 == m) {
state[cnt++] = k;
return;
}

dfs(k, p + 1); //不放

if((k & (1 << p)) || (k & (1 << (p + 1)))) return; //有障碍无法横着放

dfs(k | (3 << p), p + 1); //横着放
}

int main() {
cin >> n >> m;

do {
if(((n * m) & 1) == 1) cout << 0 << endl; //总格子数为奇数,不可能摆满
else {
memset(f, 0, sizeof f);
cnt = 0;
dfs(0, 0); //初始化第一行状态

for(int i = 0; i < cnt; i++) f[1][state[i]] = 1;

int upperLim = 1 << m; //把2^m保存起来避免重复计算

for(int i = 1; i < n; i++)
for(int j = 0; j < upperLim; j++)
if(f[i][j]) { //如果第i行状态j不可行则不考虑
cnt = 0;
dfs(upperLim - j - 1, 0); //找出状态j下一行可能的所有状态

for(int k = 0; k < cnt; k++)
f[i + 1][state[k]] += f[i][j];
}

cout << f[n][upperLim - 1] << endl; //填满的可能方案总数
}

cin >> n >> m;
} while(n != 0 && m != 0);

return 0;
}

0 0