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;
}