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

版权声明:欢迎学习我的博客,希望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;
}

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/84779871