POJ2411

题目大意

给定一个N*M大小的地板,要求你用1*2大小的砖块把地板铺满,问你有多少种方案?

题解

刚开始时看的是挑战程序设计竞赛上的关于铺砖块问题的讲解,研究一两天楞是没明白它代码是怎么写的,智商捉急,上面是用逐格进行转移的,据说神马插头DP。。。坑爹啊。。。然后果断放弃研究了。。。我们还是逐行的进行转移,这样比较好理解,方程表示为:dp[i][j]+=dp[i-1][k](能够从上一行的状态k转移到当前状态j)。我们需要枚举出符合要求的状态j和k,如果第i-1行p列没有放,那么第i行的p列肯定需要放置一个竖块,如果第i-1行p列放了,那么i行的p列可以不用放,如果第i-1行的p列和p+1列都放了,那么我们可以在第i行的p列和p+1列横着放置一个砖块。

我们用dfs实现,那么上述三种情况可以分别表示为

dfs(step+1,s1<<1|1,s2<<1,line); 竖放
dfs(step+1,s1<<1,s2<<1|1,line);不放
dfs(step+2,s1<<2|3,s2<<2|3,line);横放

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 15
typedef long long LL;
LL dp[MAXN][1<<MAXN];
int n,m;
void dfs(int step,int s1,int s2,int line)
{
    if(step==m)
    {
        dp[line][s1]+=dp[line-1][s2];
        return;
    }
    dfs(step+1,s1<<1|1,s2<<1,line);
    dfs(step+1,s1<<1,s2<<1|1,line);
    if(step+2<=m)
        dfs(step+2,s1<<2|3,s2<<2|3,line);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF&&(n+m))
    {
        memset(dp,0,sizeof(dp));
        dp[0][(1<<m)-1]=1;
        for(int i=1; i<=n; i++)
            dfs(0,0,0,i);
        printf("%I64d
",dp[n][(1<<m)-1]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zjbztianya/p/3446410.html