牛客 小乐乐搭积木
链接:https://ac.nowcoder.com/acm/contest/301/B
来源:牛客网
题目描述
小乐乐想要给自己搭建一个积木城堡。
积木城堡我们假设为n*m的平面矩形。
小乐乐现在手里有1*2,2*1两种地砖。
小乐乐想知道自己有多少种组合方案。
输入描述:
第一行输入整数n,m。(1<=n,m<=10)
输出描述:
输出组合方案数。
示例3
输出
复制8
状压dp
但是之前写铺砖的时候写的很复杂,做这道题的时候看了一下别人的博客用的搜索来找转移状态,学到了。
状压dp利用二进制来表示状态,适用于 n, m 较小的情况(一般都小于等于10)。
在本题中用二进制 1 表示这块方格被砖块覆盖了(不管他是被从哪里过来的砖覆盖的,从上面,下面还是左面都是一样的)用 0 来表示没有被覆盖。
dp[i][j]表示第i列对下一列的影响为j。 j需要被二进制展开,展开后成 (1/0)*2^(m-1),(1/0)*2^(m-2),....(1/0)*2^0
假设 2^(m-1) 的系数为 1 ,这意味着第i行的第m块方块是被一个横着放的1*2砖块覆盖了,所以才对(i+1)行的第m块方块有影响
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 6 long long dp[11][1050]; 7 int to[10050][2]; 8 int num = 0; 9 int n, m; 10 void dfs(int l,int pre, int now){ 11 if(l>m) 12 return ; 13 if(l==m){ 14 to[++num][0] = pre; 15 to[num][1] = now; 16 return ; 17 } 18 dfs(l+1,pre<<1,now<<1|1); 19 dfs(l+2,pre<<2,now<<2); 20 dfs(l+1,pre<<1|1,now<<1); 21 } 22 int main(){ 23 scanf("%d%d",&n,&m); 24 memset(dp,0,sizeof(dp)); 25 dp[0][0] = 1; 26 if(n>m)swap(n,m); 27 dfs(0,0,0); 28 for(int i=1;i<=n;i++){ 29 for(int j=1;j<=num;j++){ 30 dp[i][to[j][1]] += dp[i-1][to[j][0]]; 31 } 32 } 33 printf("%lld\n",dp[n][0]); 34 return 0; 35 }