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

 

转载于:https://www.cnblogs.com/lalalatianlalu/p/9696394.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值