版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/84779871
题干:
小乐乐想要给自己搭建一个积木城堡。
积木城堡我们假设为n*m的平面矩形。
小乐乐现在手里有1*2,2*1两种地砖。
小乐乐想知道自己有多少种组合方案。
输入描述:
第一行输入整数n,m。(1<=n,m<=10)
输出描述:
输出组合方案数。
示例1
输入
2 3
输出
3
说明
示例2
输入
1 3
输出
0
示例3
输入
2 5
输出
8
解题报告:
这题状压dp,,那种很传统的方法就不贴了,,今天来贴一个更快的方法、、不同点不在于预处理第一行,而是下面的行,也就是直接找到第二行所有符合的状态,顺便找到对应上一行应该有的状态,直接做和就可以了。
AC代码:
/*优化:不去盲目的列举所有状态i和j然后判断状态j能否到达i,这样效率很低,因为能到达i的状态j很少
因此对于每种状态i,由i区搜索能到达i的状态j,大大提高效率
有298ms->32ms
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <iomanip>
#define INF 0x3f3f3f3f
typedef long long LL;
using namespace std;
const int MAX=(1<<11)+10;
int n,m;
LL temp[MAX],dp[MAX],biao[15];
bool check(int i){
while(i){
if(i&1){
i>>=1;
if(!(i&1))return false;//第j列是1则第j+1列必须是1
i>>=1;//继续判断下一列
}else i>>=1;//继续判断下一列
}
return true;
}
void Init(){
memset(temp,0,sizeof temp);
for(int i=0;i<biao[m];++i)if(check(i))temp[i]=1;//初始化第一行
}
void dfs(int lie,int now,int cur) {
if(lie == m) {
dp[now] += temp[cur];return ;
}
if((now>>lie) & 1) {
dfs(lie+1,now,cur);
if((now>>(lie+1)) & 1) dfs(lie+2,now,cur|(1<<lie)|(1<<(lie+1)));
}
else dfs(lie+1,now,cur|(1<<lie));
}
void DP(){
for(int k=2;k<=n;++k){
for(int i=0;i<biao[m];++i) dp[i]=0;
for(int i=0;i<biao[m];++i) dfs(0,i,0);
for(int i=0;i<biao[m];++i) temp[i]=dp[i];
}
}
int main(){
biao[0]=1;
for(int i=1;i<12;++i)biao[i]=2*biao[i-1];
scanf("%d%d",&n,&m);
//if(n<m)swap(n,m);//始终保持m<n,提高效率
Init();
DP();
printf("%lld\n",temp[biao[m]-1]);//输出最后一行到达时的状态必须全部是1
return 0;
}