这道题和上一道题特别相似,传送门
题意:给你若干个1*3的木块,要放满n*m的棋盘,求有多少种放法。
思路:状态压缩dp,在上一道题的基础上再再增加一维状态表示对下两行的影响。这里需要注意,避免枚举当前情况影响到本次的另一种情况,所以直接加一个参数表示当前状态的放法总数,空间压得比较紧,从1到n输入会MLE。
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<<9;
const int inf=0x3f3f3f3f;
int n,m,ans,k,T;
long long dp[31][mx][mx];
void dfs(int i,int j,int now,int nex,int next,long long sum)
{
if(j==m){
dp[i+1][nex][next]+=sum;//直接用sum防止本次枚举的这一种情况影响本次枚举的另一种情况
return ;
}
if(now&1<<j) dfs(i,j+1,now,nex,next,sum);
if(!(now&1<<j)&&!(nex&1<<j)) dfs(i,j+1,now,nex|1<<j,next|1<<j,sum);//放一个1*3的,对后面两行都有影响
if((j+2<m)&&!(now&1<<j)&&!(now&1<<(j+1))&&!(now&1<<(j+2))) dfs(i,j+3,now,nex,next,sum);//连续三个位置都没放木块,可以放一个3*1的
}
int main() {
int t,j,k,l,q,x,y,ss,h;
int cas=1,flag,f1;
while(scanf("%d%d",&m,&n)&&(m||n))
{
memset(dp,0,sizeof(dp));
ans=0;
dp[0][0][0]=1;
for(int i=0;i<n;i++) {//注意从0到n-1,1-n就会MLE
for(int j=0;j<1<<m;j++)
{
for(int k=0;k<1<<m;k++)
if (dp[i][j][k]) dfs(i,0,j,k,0,dp[i][j][k]);
}
}
printf("%lld\n",dp[n][0][0]);
}
return 0;
}