dp[r][k]代表第r行的占有情况是二进制k(0为空,1为已占)....每次更新枚举每行的情况..看怎么来摆..首先要保证摆的自我不冲突.然后它的更新来源可以推出来(因为每个方块最多影响其上一层的..而题目要求必须所有位置都填满..那么确定了本行的放置情况,其中竖着放回占有上面一行的一格,所以上行对应的就是0....不放或横着放必须保证上面已经占有.即上一行对应位置为1..)...
Program:
#include<iostream> #include<stdio.h> #include<string.h> #include<set> #include<algorithm> #include<cmath> #define oo 1000000007 #define ll long long #define pi acos(-1.0) #define MAXN 505 using namespace std; int h,w,canuse[14000],num; ll dp[15][2148]; bool legal(int x) { int i,a[15]; memset(a,0,sizeof(a)); for (i=1;i<=w;i++) { if (x%3==1) a[i]++; if (x%3==2) a[i]++,a[i+1]++; x/=3; } if (a[w+1]>0) return false; for (i=1;i<=w;i++) if (a[i]>1) return false; return true; } bool canput(int x) { x=canuse[x]; while (x) { if (x%3==1) return false; x/=3; } return true; } int findit(int x) { int i,data=0,t=1; x=canuse[x]; for (i=1;i<=w;i++) { if (x%3!=1) data+=t; x/=3; t*=2; } return data; } int _to2(int x) { int i,a[13],data; memset(a,0,sizeof(a)); x=canuse[x]; for (i=1;i<=w;i++) { if (x%3==1) a[i]=1; if (x%3==2) a[i]=1,a[i+1]=1; x/=3; } data=0; for (i=1;i<=w;i++) data+=a[i]*(1<<(i-1)); return data; } int main() { int i,r,j,totol; while (~scanf("%d%d",&h,&w)) { if (!h && !w) break; totol=1; for (i=1;i<=w;i++) totol*=3; num=0; for (i=0;i<totol;i++) if (legal(i)) canuse[++num]=i; memset(dp,0,sizeof(dp)); for (i=1;i<=num;i++) if (canput(i)) dp[1][_to2(i)]=1; for (r=2;r<=h;r++) for (i=1;i<=num;i++) dp[r][_to2(i)]+=dp[r-1][findit(i)]; printf("%I64d\n",dp[h][(1<<w)-1]); } return 0; }