题目大意
给定一个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; }