题意:
求一个 n*m 的矩形用 1*2 的矩形进行覆盖的方法总数
分析:
状态压缩
dp[r][k]表示第r行的 凸出状态为k(竖着) 时,前r行最多的方案数,结果就是dp[row-1][0](row从0开始)
//AC CODE:
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<map>
using namespace std;
int cnt, stk[150];
//dp[r][k]表示第r行的 凸出状态为k(竖着) 时,前r行最多的方案数,结果就是dp[row-1][0](row从0开始)
__int64 dp[15][2050];
int get_bit(int num, int index)//取num中的index位
{
return (num>>(index))&1;
}
bool ok(int n, int x)//检查x是否合法,是否连续出现奇数个0
{
int count=0;
for(int i=0; i<n; i++)
{
if(get_bit(x,i)==0)
count++;//x中的第i位是0
else
{
if(count%2!=0)
return 0;
count=0;
}
}
if(count%2!=0)//没写这两句话,悲剧了很久。。。
return 0;//
return 1;
}
void findStk(int n)//1表示竖着放,0表示横着放,0需要成对出现
{
for(int i = 0; i < (1<<n); i ++)
if(ok(n, i))//检查i是否合法
stk[cnt ++] = i;
}
int main()
{
int row, col, r, i, k;
while(scanf("%d %d",&row,&col)!=EOF&&(row||col))
{
if((row*col%2)==1)
{
printf("0\n");
continue;
}
memset(dp, 0, sizeof(dp));
cnt = 0;
findStk(col);
//第一行
for(i = 0; i < cnt; i ++)
dp[0][stk[i]] = 1;//stk[i]竖着的状态
//其它行
for(r = 1; r < row; r ++)
for(i = 0; i < cnt; i ++)
{
for(k = 0; k < (1<<col); k ++)
{
if((stk[i] & k) != k)//该行(stk[i])可以添加到上一行(k)的下面
continue;
dp[r][stk[i]^k] += dp[r-1][k];//stk[i]^k为凸出状态 异或:相同取0,相异取1
}
}
printf("%I64d\n", dp[row-1][0]);
}
return 0;
}