zoj 2563 Long Dominoes (状态压缩dp)

来源:互联网 发布:gprs网络通信模块收费 编辑:程序博客网 时间:2024/06/03 17:36

这道题和上一道题特别相似,传送门

题意:给你若干个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;
}