蓝桥杯真题训练 五一 2/5

1212 地宫取宝

可真是醉了。
这是记忆化搜索的题目,为了弄懂,又花了不少时间。
记忆化搜索=深搜+动态规划
题目要求的只能向下或者向右,所有只用了两个坐标。
其实取模每次都应该取的,但是居然只在结果取模没爆,就没改。

解题步骤:

题目要求取k个物品,且每次取都不能比之前取过的所有物品的最大值小,可以在路径上选择取或者不取。
设方程:dp[x][y][num][val] =n — 表示(x,y)位置下取了num个物品,当前最大物品的价值为val的情况下,共有n种情况。
(1)考虑到不取也是一种情况,相当于在该位置 +0,所以首先把dp数组初始成 -1,代表没走过当前位置。再考虑如果走到当前位置,数组下标不能为 -1,所以再把所有的maxval值 +1。
(2)给深搜设置出口,一定是走到右下角的位置,即(x=n && y=m),到出口了进行判断,有两种可行情况,一种是num=k,已经正好选了k个,最后一个不选;另一种是num=k-1 & 右下角物品的值大于val的值,已经正好选了k-1个,最后一个物品还能被选择。其余情况皆不满足条件。满足条件返回1,代表情况数 +1,不满足条件返回0。
(3)对于每个(x,y)的位置,都可以有两种情况,要么向下,要么向右。每种情况判断一下边界值,以及当前的物品是否可选,可选就选或不选两种情况都放进去递归,不可选就一种放进去递归。
因为深搜是搜到终点后不断向回传递的,就像(3)种的(x,y),是向后或向右的总情况数传递回来,再加到当前的情况数中,所以有了一个sum,累加情况数,最后把得到的结果赋给dp数组。也正是从右下角(终点)向回传递,才有最终的答案是dp[1][1][0][0]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=55;
const int N=15;
int maps[maxn][maxn];
int dp[maxn][maxn][N][N];
int dir[2][2]={
    {1,0},{0,1}
};
int n,m,k;
int dfs(int x,int y,int num,int val){
    if(dp[x][y][num][val+1]!=-1){
        return dp[x][y][num][val+1];
    }
    if(x==n&&y==m){
        if(num==k||(num==k-1&&maps[x][y]>val)){
            return 1;
        }
        return 0;
    }
    long long sum=0;
    for(int i=0;i<2;i++){
        int xx=x+dir[i][0];
        int yy=y+dir[i][1];
        if(xx<=n&&yy<=m){
            if(maps[x][y]>val) sum+=dfs(xx,yy,num+1,maps[x][y]);
            sum+=dfs(xx,yy,num,val);
        }
    }
    return dp[x][y][num][val+1]=sum%mod;
}
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>maps[i][j];
        }
    }
    memset(dp,-1,sizeof(dp));
    dfs(1,1,0,-1);
    cout<<dp[1][1][0][0];
    system("pause");
    return 0;
}

1215 小朋友排队

今天晚点补,刚打了牛客的比赛。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值