参考:http://blog.csdn.net/woshi250hua/article/details/7952496
状态转移方程:dp[i+1][k]=sum(dp[i][j]);对于每一行,因为最多有11列,所以最多有2^11=2048个状态,由于一行的状态只受前一行状态的影响,因此关键是j如何才能转向k。本题目采用的是插头dp,如果某个位置为0表示该位置是一个插头,可以将木块竖着放。否则,必须有连续偶数个1才行。
边界条件:可以将第0行预设为全是1,终态为最后一行全部为1,dp[h][2^w-1]。
程序中,枚举每个状态是否可行。另,交换h,w是的h<=w会使速度更快。
//11217061 c00h00g 2411 Accepted 580K 860MS G++ 937B 2013-01-28 18:06:34
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int h,w;
__int64 dp[12][2048];
int isOk(int from,int to){
for(int i=0;i<w;i++){
int x=from&(1<<i);
int y=to&(1<<i);
if(!x&&!y) return 0;
if(x&&y){
i++;
if(i==w) return 0;
if((from&(1<<i))==0) return 0;
if((to&(1<<i))==0) return 0;
}
}
return 1;
}
int main(){
while(scanf("%d%d",&h,&w)!=EOF){
if(h==0&&w==0) break;
if(h%2&&w%2) { printf("0\n");continue;}
int Max=(1<<w)-1;
memset(dp,0,sizeof(dp));
dp[0][Max]=1;
for(int i=0;i<h;i++)
for(int j=0;j<=Max;j++)
if(dp[i][j])
for(int k=0;k<=Max;k++)
if(isOk(j,k))
dp[i+1][k]+=dp[i][j];
printf("%I64d\n",dp[h][Max]);
}
return 0;
}