蓝桥杯搭积木java_[蓝桥杯][2018年第九届真题]搭积木-题解(C++代码)

解题思路:

首先根据题目中的规则一,可以推出在搭积木是底层就决定上层的宽度。那我们可以把解决问题的出发点定义在最下层。先把最下层的字符根据X划分成多个连续.的区间,然后讨论每个区间满足其他规则的数目,然后运算(这里还不能确定相加)。

对于每个确定宽度区间,我们可以从一遍进行搜索,当然也不是盲目搜索。如果使用单纯的搜索的话,其中会存在大量重复搜索的数据,这些重复的数据会大大提高搜索的时间,于是我们采用记忆化搜索,就是将已经搜索过的位置进行数据保存保存在一个二维数组中(dp[b][c]在二维数组中,b代表第几列,c代表第几层)

对于在搜索的方向,我是从右到左。当搜索到(b,c)的时候,当前列的高度就确定了,那么改变摆放积木的方法的数量只与右边相邻的一列有关,dp[b][c]+=dp[b][h[b]](h数组保存某一列可到达最高的高度。)

规则二:同一层积木必须连续摆放,这就是表明在一段区间内的积木摆放情况不会存在每列最高的积木先下降后上升。对于这个的规则,我们还要加一个判断。判断的方法不知一种,我的方法是在刚才的dp数组的基础上在加一维,变成三维数组。dp[a][b][c]b,c表示含义不变。a有两个值,一个是0代表前面已经出现下降不能再有上升,另一个是1代表前面没出现下降。

在进行搜索过程中就需要判断a是否为0。如果是0:dp[a][b][c]+=dp[a][b+1][c],如果是1:dp[a][b][c]+=dp[a][b+1][c]

规则二还有一部分就是中间不能有空隙,说明两个独立的区间不能同时摆放,也就是不同区间的计算结果进行相加。

规则三就是说明每一列的最高点。一位在“X”的上面的.是不能摆放积木的(如果摆放就违反规则一)。

注意事项:

对于规则二判断下降的方法,可以使用一个标记数字。当题目给出的n,m太大时,我的方法可能会内存超限。

参考代码:

#include"iostream"

#include"cstdio"

#include"string.h"

#define mod 1000000007

using namespace std;

int n,m,r,h[1000],num=0;

int dp[3][100][100];

char s[1000][1000];

void col_height(){

for(int i=1;i<=m;i++){

int hi=0;

for(int j=n;j>=1;j--){

if(s[j][i]=='X')

break;

hi++;

}

h[i]=hi;

}

return ;

}

int dfs(int sta,int pos,int last){

if(pos>r){

return 1;

}

if(dp[sta][pos][last]!=-1)

return dp[sta][pos][last];

int sum=0;

for(int i=1;i<=h[pos];i++){

if(i>last){

if(sta==1)

sum=(sum+dfs(1,pos+1,i))%mod;

}else if(i==last){

sum=(sum+dfs(sta,pos+1,i))%mod;

}else

sum=(sum+dfs(0,pos+1,i))%mod;

}

return dp[sta][pos][last]=sum;

}

int main(){

scanf("%d%d",&n,&m);

for(int i=1;i<=n;i++){

for(int j=1;j<=m;j++){

cin>>s[i][j];

}

}

col_height();

int i=1;

while(i<=m){

if(s[n][i]=='X'){

i++;continue;

}

int j=i;

while(j<=m&&s[n][j]=='.'){

j++;continue;

}

j--;

for(r=j;r>=i;r--){

memset(dp,-1,sizeof(dp));

for(int l=r;l>=i;l--){

num=(num+dfs(1,l,1))%mod;

}

}

i=j+1;

}

cout<

return 0;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值