题目链接:http://poj.org/problem?id=2411
题意:由1*2 的矩形通过组合拼成大矩形,求拼成指定的大矩形有几种拼法。
分析:如果是横着的就定义11,如果竖着的定义为竖着的01,状态兼容时只需考虑两种情况,当前行|上一行,是不是全为1,不是说明竖着有空(不能出现竖着的00),然后再当前行&上一行,这里被消掉的1全部用来竖着放的,判断之后的状态是否有奇数的连续1,有则不能转移的,因为剩下的都是用来行着放了。
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 100000000
#define inf 0x3f3f3f3f
#define eps 1e-9
#define N 100010
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
LL dp[][<<];
int fit[<<];
int tot,n,m;
bool ok(int x)//判断一行状态中是否有奇数的连续1
{
int opp=;
while(x)
{
if(x&)opp++;
else
{
if(opp&)return ;
opp=;
}
x>>=;
}
return (opp&)==;
}
bool judge(int j,int k)
{
if((j|k)!=(<<m)-)return false;
return fit[j&k];
}
int main()
{
for(int i=;i<(<<);i++)if(ok(i))fit[i]=;
while(scanf("%d%d",&n,&m)>)
{
if(n+m==)break;
FILL(dp,);
if(m*n&)
{
puts("");continue;
}
if(n<m)swap(n,m);
for(int i=;i<(<<m);i++)
dp[][i]=fit[i];
for(int i=;i<=n;i++)
{
for(int j=;j<(<<m);j++)
for(int k=;k<(<<m);k++)
if(judge(j,k))
dp[i][j]+=dp[i-][k];
}
printf("%lld\n",dp[n][(<<m)-]);
}
}