题意:给一个n*m(1<=n,m<=11)的棋盘,用1*2的木块往上放,要放满整个棋盘,求一共有多少种放法。
思路:状态压缩dp。1表示放,0表示不放。第i行状态只与第i-1行有关,因此用dp[i][state]表示第i行状态为state的放法总数。直接枚举每一行的放法和对下一行的影响,最后dp[n+1][0]就是答案。(想想是不是)注意要用long long。
AC代码:
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
const int mo=1e9+7;
const int mx=1<<11;
const int inf=0x3f3f3f3f;
int n,m,ans,k,T,i;
long long dp[15][mx];
void dfs(int j,int now,int nex)
{
if(j==m){
dp[i+1][nex]+=dp[i][now];
return ;
}
if(now&1<<j) dfs(j+1,now,nex);//这一格已经放了木块,跳过
if(!(now&1<<j)) dfs(j+1,now,nex|1<<j);//这一格没放,放一个1*2的
if((j+1<m)&&!(now&1<<j)&&!(now&1<<(j+1))) dfs(j+2,now,nex);//这一格和下一格都没放,放一个2*1的
}
int main() {
int t,j,k,l,q,x,y,ss,h;
int cas=1,flag,f1;
while(scanf("%d%d",&n,&m)&&(m||n))
{
//getchar();
if((m*n)&1) puts("0");//m*n为奇数时是放不满的,想想是不是
else {
memset(dp,0,sizeof(dp));
ans=0;
dp[1][0]=1;
for(i=1;i<=n;i++) {
for(int j=0;j<1<<m;j++)
{
if (dp[i][j]) dfs(0,j,0);//我这里是枚举每一行的状态,枚举每一列也可以,因为这里n,m都比较小
}
}
printf("%lld\n",dp[n+1][0]);
}
}
return 0;
}