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.
<center>
</center>
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!
<center>
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
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
今天晚上状态超级不好啊==本文参考:点击打开链接
题意:用1x2的方块密铺nxm的矩形,问方法数,一看题就想到了hdu2946骨牌铺方格,只不过那个题是只有两行,其实只有两行就足以找出规律:
1.假设已知Fibo(n),如果将第n+1块板竖着插入排头,会发现并没有多出组合,Fibo(n+1)=Fibo(n),插入其他位置的情况下, 如果第n+1个位置是竖板,等同于前面的情况。 2.只有在n和n+1的位置是横板,才能多出组合,多的组合数量为Fibo(n-1); 3.推出 Fibo(n+1)=Fibo(n)+Fibo(n-1);即为Fibo(n)=Fibo(n-1)+Fibo(n-2);
同理我们考虑不止两行的情况,假设枚举到了第i行,前i-2行已经密铺了,将每行的骨牌有无压缩至一个十进制的二进制对应位,这个so easy吧,ss,s分别表示上行i-1状态和本行i状态,就像其他的dp题一样,状态不是直接找的对应的来转化的,而是判断两个状态是否可以转化再转化,这个过程就是下面的solve。重点是ok()这个判断函数:
1.第i行的第j列为1,第i-1行的第j列为1,这样的话,说明第i行的第j列一定不是竖放而是横放否则会与第i-1行的第j列冲突
所以马上紧接着判断第i行第j+1列,如果是1,那么满足横放的规则,同时也要第i-1行第j+1列也要为1,否则的话这个格子没办法填充,
成立后向左移动两格
不满足上述条件的,就是两个不兼容或者不合法的状态
2.第i行第j列为1,第i-1行第j列为0,那么说明第i行第j列应该竖放并填充第i-1行第j列,成立后向左移动一格
3.第i行第j列为0,说明不放方块,那么第i-1行第j列必须为1,否则没法填充这个格子。若第i-1行第j列也为0,不兼容不合法
(至于第i行第j列这个格子空着干什么,其实就是留出来给第i+1行竖放的时候***来的)
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 15
#define MAX (1<<11)+10
long long dp[N][MAX];
long long ans[N][N];
int n,m;
bool init(int s)
{
for(int i=0;i<m;)
{
if(s&(1<<i))
{
if(i==m-1) return false;
if(s&(1<<(i+1)))i+=2;
else return false;
}
else i++;
}
return true;
}
bool ok(int s,int ss)
{
for(int i=0;i<m;)
{
if(s&(1<<i))
{
if(ss&(1<<i))
{
if(i==m-1||!(s&(1<<(i+1)))||!(ss&(1<<(i+1))))return false;
i+=2;
}
else i++;
}
else
{
if(ss&(1<<i))i++;
else return false;
}
}
return true;
}
void solve()
{
if(n<m) swap(m,n);
memset(dp,0,sizeof(dp));
int maxn=(1<<m)-1;
for(int i=0;i<=maxn;i++)
if(init(i))
dp[1][i]=1;
for(int i=2;i<=n;i++)
for(int s=0;s<=maxn;s++)
for(int ss=0;ss<=maxn;ss++)
if(ok(s,ss))
dp[i][s]+=dp[i-1][ss];
printf("%I64d\n",dp[n][maxn]);
}
int main()
{
//freopen("cin.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
if(m==0&&n==0) break;
if(m*n%2)
{
printf("0\n");
continue;
}
solve();
}
return 0;
}