首页 > 代码库 > 状压DP入门——铺砖块

状压DP入门——铺砖块

题目描述

现有n*m的一块地板,需要用1*2的砖块去铺满,中间不能留有空隙。问这样方案有多少种 

技术分享

 

输入

输入n,m(1<=n, m<=11) 
有多组输入数据,以m=n=0结束 

 

输出

输出铺砖块的方案数

 

样例输入

1 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0

样例输出

1 0 1 2 3 5 144 51205
我A的第一道状压DP题是导游,感觉就是背包~~
此题不是很懂
此题状压DP,DP[i][sta]表示前i行填满对第i+1行的影响为状态sta时的方案总数
易知DP[0][0]=1;目标值f[i][0];
关于sta:sta表示当前此行对下一行的影响
定义竖铺时上一行为1,这一行为0;横铺时均为0;
可以推得状态若上一行为1,这一行必为0(竖铺一块嘛);
若上一行为0,可以竖铺一块填满下面的一块,这样下一行就为0;
若上一行为00,下一行为00;
关于DP的转移:dfs生成每个前一行和后一行的状态
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
long long  n,m,num,dp[150][40970],change[40970][20];
void dfs(int l,int pre,int now)
{
    if(l>m)
    return;
    if(l==m)
    {
        change[++num][0]=pre;
        change[num][1]=now;
    }
    dfs(l+1,pre<<1,now<<1|1);
    dfs(l+2,pre<<2,now<<2);
    dfs(l+1,pre<<1|1,now<<1);
}
int main()
{
    //f[i][sta]琛ㄧず鍓峣琛屽~婊″绗琲+1鐨勫奖鍝?
    while(~scanf("%d %d",&n,&m)&&n!=0&&m!=0)
    {
        if(n>m) swap(n,m);
        num=0;
        dfs(0,0,0);
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        rep(i,1,n)
        
        {
            rep(j,1,num)
            {
                dp[i][change[j][1]]+=dp[i-1][change[j][0]]; 
            }
        }
        printf("%lld\n",dp[n][0]);
    }
 }

 

 
 
 
 

状压DP入门——铺砖块