Z - Mondriaan's Dream
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
题意:有1*2或2*1的长方块组成h*w的大方块 的方案有多少种
如上图所示,一个状态由w位(k4k3k2k1k0)的二进制数组成,ki=1表示ki的位置被方块占有,每次遍历一个点(i,j)作为当前状态(k3k2k1k0O)的最后一个值,对于各种存在的k4k3k2k1k0,这里定义dp[cur][k3k2k1k0O]表示在当前状态k4k3k2k1k0下的方案数,cur有0和1两个值,取反cur=cur^1,得到另外一个cur值,可以用cur^1表示上一组状态
(1)如果k4=0,则必须向上放,则dp[cur][k3k2k1k01]+=dp[cur^1][k4k3k2k1k0] (此种方案下,k4变为1)
(2)如果k4=1且k0=0,则可以选择向左放,有dp[cur][k3k2k111]+=dp[cur^1][k4k3k2k1k0],
或选择不放则dp[cur][k3k2k100]+=dp[cur^1][k4k3k2k1k0]
以O(1,1)为右下角的时候,在O位置只能选择不放,而初始化的开始条件是dp[cur^1][11111]=1,表示与此次对接的方案数为1
每次以O为右下角,保证O放完K4是1,而k3k2k1k0O是01二进制数,并且保存当前各个符合要求的01二进制(用十进制表示)下的状态的方案数,最后O到达最右下角的时候,取dp[cur][11111]即为总的方案数。
#include<cstdio>
#include<stack>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<iostream>
#include<cmath>
using namespace std;
#define inf 0x3f3f3f3f
#define mod 100000000
typedef long long ll;
const int nmax=44;
const double esp = 1e-9;
const int N=12;
int n,m;
ll dp[2][1<<N];
void solve()
{
int top=(1<<m)-1;
memset(dp,0,sizeof(dp));
dp[0][top]=1;
int cur=0,state;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
cur^=1;
memset(dp[cur],0,sizeof(dp[cur]));
for(int k=0; k<=top; k++) //遍历上一组状态
{
if(i!=1&&!(k&(1<<(m-1)))) //往上放,当前不是第一行且上面那个一个(上一个状态第一位)为0
{
state=(((k<<1)|1)&((1<<m)-1));
dp[cur][state]+=dp[cur^1][k];
}
if(j!=1&&(k&(1<<(m-1)))&&!(k&1)) //往左放,当前不是第1列且上面那个一个(上一个状态第一位)为1
{
state=(((k<<1)|3)&((1<<m)-1));
dp[cur][state]+=dp[cur^1][k];
}
if(k&(1<<(m-1))) //不放,上面那个一个(上一个状态第一位)为1
{
state=((k<<1)&((1<<m)-1));
dp[cur][state]+=dp[cur^1][k];
}
}
}
}
printf("%lld\n",dp[cur][top]);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0)
break;
if(n<m)
{
int t=m;
m=n;
n=t;
}
solve();
}
return 0;
}