参考: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; }