高中就用PASCAL写过,但现在忘了,只记得是2进制状态压缩,却始终想不用如何具体维护两个状态的转移。
于是乎,参考了别人的代码,看到一种表示方法是:0表示横向(必然两个0连续),1表示纵向,(另外DP时1特指向下凸,)那么放满一行的state数是有限的,且远小于2^w,如果状态j对应statej可以从状态k推过来,那一定有k& ~statej == 0,(此处注意理解,是关键,若k对应r位上是1,则statej上也为1,取反在and则为0,若k上连续两个0,则statej对应连续两个0,取反再and则为11,故成立。)
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cstring>
using namespace std;
#define N 11
#define M 2048
long long f[N+5][M+5];
int state[M+5];
int h,w,js,sum;
void dfs(int pos,int data)
{
if (pos==w) {
state[js++]=data;
return ;
}
if (pos+2<=w) dfs(pos+2,data);
dfs(pos+1,data+(1<<pos));
}
void DP()
{
memset(f,0,sizeof(f));
for (int i=0;i<js;i++){
f[0][state[i]]=1;
}
for (int i=1;i<h;i++)
for (int j=0;j<js;j++)
for (int k=0;k<sum;k++){
if (f[i-1][k] && !(k&(~state[j])))
f[i][state[j]-k]+=f[i-1][k];
}
}
int main()
{
freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
cin>>h>>w;
while (!(h==0 && w==0)){
sum=1;
for (int i=0;i<w;i++) sum*=2;
js=0;
dfs(0,0);
DP();
printf("%I64d\n",f[h-1][0]);
cin>>h>>w;
}
return 0;
}