0
点赞
收藏
分享

微信扫一扫

【牛客 - 301哈尔滨理工大学软件与微电子学院第八届程序设计竞赛同步赛(高年级)】小乐乐搭积木(状压dp)

题干:
 

小乐乐想要给自己搭建一个积木城堡。

积木城堡我们假设为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;
}

 


举报

相关推荐

0 条评论