状压dp 棋盘问题的学习

有一个N*M(N<=5,M<=1000)的棋盘,现在有1*2及2*1的小木块无数个,要盖满整个棋盘,有多少种方式?答案只需要mod1,000,000,007即可。

//我也不知道这道题的来源QAQ

N和M的范围本应是相同的,但是题目给出的N的值很小,这就给我们提供了使用状压DP的思路。

假设第一列已经铺满,则第二列的情况只与第一列对它的影响有关,同理,第三列的情况也只与第二列对它的影响有关,我们可以利用二进制来表示某一列的情况,状态state表示某一列的状态,例如state=4,则此列状态为00100,用dp[i][state]表示第i列,第i-1列对它的影响为state的方案数,求每一列的方案数可以通过搜索来实现,dp[i][state]=sigma(dp[i-1][la]) la可以通过填放变为state。

//铺棋盘
//2015/10/22 
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<cstring>
#include<algorithm>
#define maxn 100000000+50
#define inf 0x7fffffff
#define  xiao 1e-9
#define mod 1000000007
using namespace std;
int dp[1005][40],n,m;
void dfs(int i,int j,int state,int next)
{
    if(j==n) 
    {
        dp[i+1][next]+=dp[i][state];
        dp[i+1][next]%=mod; 
        return;
    }//如果枚举到了最后一行,则下一列状态为next时方案数加上此列状态为state的方案数
    if(((1<<j)&state)>0) dfs(i,j+1,state,next);//如果第j行位置已被占用,直接跳过,搜索j+1行
    if(((1<<j)&state)==0) dfs(i,j+1,state,next|(1<<j));//如果未被占用,尝试填放一个1*2的
    if(j+1<n&&((1<<j)&state)==0&&((1<<(j+1)&state)==0)) dfs(i,j+2,state,next);//如果此位置以及下一位置都未被占用,尝试放一个2*1的
    return;
}
int main()
{
    cin>>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)
        {
            if(dp[i][j])  dfs(i,0,j,0);
                    }
    cout<<dp[m+1][0]<<endl;
    return 0;
 }


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值