状压dp(不知道哪里的题目)

这是一道流传至今的状压dp,好像很多人都不知道他的源头在哪里,但是他作为状压dp的入门却是口口相传,他就是一个经典的贴瓷砖问题

题目:有一个N*M(N<=5,M<=1000)的棋盘,现在有1*2及2*1的小木块无数个,要盖满整个棋盘,有多少种方式?答案对某个数取模。

思路:我们可以看到有一维很小,小到可以状压(滑稽),我们当然是对一维进行状压,一维进行枚举,dfs(i,j,state,nxt)代表第i列,第j行,这一行想填成的状态为state,以及填成state时下一列的状态为nxt

然后我们就可以愉快的转移了(反正大体的思路了就是这样,我也不知道我写的对不对)

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int MOD=1e9+7;
int n,m;

LL dp[1005][35];
void dfs(int i,int j,int state,int nxt)
{
    if(j==n){
        dp[i+1][nxt]+=dp[i][state];
        dp[i+1][nxt]%=MOD;
        return ;
    }
    if(((1<<j)&state)==1)dfs(i,j+1,state,nxt);
    if(((1<<j)&state)==0)dfs(i,j+1,state,nxt|(1<<j));
    if(j+1<n&&(((1<<j)&state)==0)&&(((1<<(j+1)&state)==0)))
        dfs(i,j+2,state,nxt);
}

int main()
{
    while(~scanf("%d%d",&n,&m)){
        memset(dp,0,sizeof(dp));
        dp[1][0]=1;
        for(int i=1;i<=m;i++){
            for(int j=0;j<=(1<<n);j++){
                dfs(i,0,j,0);
            }
        }
        printf("%lld\n",dp[m+1][0]);
    }
    return 0;
}

 

posted @ 2018-09-24 19:51  啦啦啦天啦噜  阅读(414)  评论(0编辑  收藏  举报