1、st中存的是每一行摆放的所有可能,0是空着,1是占着,st[i][0]中存一行的可能的状态即from,st[i][1]中存与其匹配的下一行状态即to;
2、dfs中from是一行中前n个格子的状态,to是与之吻合的状态;
3、因为只看每一行的可能状态,所以dfs中的n==w时已取完该种可能,退出递归;
4、对于一行的第n列,采取三种摆放长方形的方式
dfs(n+2,(from<<2)+3,(to<<2)+3); //横着放,这层和下一层匹配的都多两位1 (二进制11就是3嘛)
dfs(n+1,(from<<1)+1,to<<1);//竖着放,这层多一个1,匹配下层这个位置是0
dfs(n+1,from<<1,(to<<1)+1);//不放,这层多一个0,匹配的下层多个1
5、dp[i][j]中存第i行摆放状态为j时的方法数,边界是要全放满的,dp[0][(1<<w)-1]=1,最后要求的是dp[h][(1<<w)-1];
6、dp过程是
for(i=1;i<=h;i++)
{
for(j=0;j<cnt;j++)
{
dp[i][st[j][1]]+=dp[i-1][st[j][0]];
}
}
#include<stdio.h> #include<string.h> int st[3000][2]; int dp[11][3000]; //2^11=2048最多的状态数 int cnt,h,w; void dfs(int n,int from,int to)//枚举所有一行摆放的可能和其匹配的下层 { if(n>w) return; if(n==w) //这一行刚好摆完,得到一行摆放的组合 { st[cnt][0]=from; st[cnt][1]=to; cnt++; return; } dfs(n+2,(from<<2)+3,(to<<2)+3); //横着放,这层和下一层匹配的都多两位1 dfs(n+1,(from<<1)+1,to<<1);//竖着放,这层多一个1,匹配下层这个位置是0 dfs(n+1,from<<1,(to<<1)+1);//不放,这层多一个0,匹配的下层多个1 } int main() { int i,j; while(scanf("%d %d",&h,&w)&&h) { if((w*h)%2) { printf("0\n"); continue; } memset(dp,0,sizeof(dp)); memset(st,0,sizeof(st)); cnt=0; //记录每一行摆放所有可能的状态总数 dfs(0,0,0); dp[0][(1<<w)-1]=1;//边界 for(i=1;i<=h;i++) { for(j=0;j<cnt;j++) { dp[i][st[j][1]]+=dp[i-1][st[j][0]]; } } printf("%d\n",dp[h][(1<<w)-1]); } return 0; }