蓝桥杯2014年第五届真题-地宫取宝【记忆性递归】

蓝桥杯2014年第五届真题-地宫取宝
X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。地宫的入口在左上角,出口在右下角。
小明被带到地宫的入口,国王要求他只能向右或向下行走。
走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。

请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
输入
输入一行3个整数,用空格分开:n m k (1< =n,m< =50, 1< =k< =12)

接下来有 n 行数据,每行有 m 个整数 Ci (0< =Ci< =12)代表这个格子上的宝物的价值
输出
要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。
样例输入
2 3 2
1 2 3
2 1 5
样例输出
14

解题思路:
以前都是用vis[ ][ ]数组判断该位置有没有被访问过,现在情况有所改动,除了位置,他还带着 “当前手中宝物价值的最大值:max” 以及 “当前手中宝物数:cnt”,所以开辟一个缓存数组cache[x][y][max][cnt]将四种状态都记录

( x , y )(x , y+1)
(x , y+1)p

比如说:(x,y)想要到达p点,是向右还是向左,是拾起(x,y)格子处的宝物还是不拾起,无论是怎么到达p点的,如果在p点发现dfs(i,j,max,cnt)中i,j,max,cnt,和缓存中的一样,那就是重复搜索了。可以采用动态规划(dp):动归数组、逐步生成或者记忆性递归,这里采用记忆性递归,因此开辟一个缓存数组。

#include<iostream>
#include<algorithm>
#include<cstring>
#define MOD 1000000007
using namespace std;
int n, m, k;
int maze[50][50];
long long ans;
long long cache[50][50][14][13];//缓存数组
long long dfs(int x, int y, int max, int cnt)//不再是void,而是返回long long 类型的方案数ans
{
    //先查缓存,缓存里有,直接用
    if (cache[x][y][max+1][cnt] != -1)//记忆化搜索,
    此处为什么max+1,因为题目中宝物价值是:Ci  (0< =Ci< =12),包含0,所以可能取到0,那我在main函数调用时初始化max只能是负数,否则如果起始点为0,我就不能拾起了,但数组下标又不能是负数,干脆直接化为max+1,max+1>=0说明拾起第一件宝物
        return cache[x][y][max+1][cnt];
    //如果越界或者当前手中宝物数大于k,退出
    if (x == n || y == m || cnt > k)
        return 0;
    int cur = maze[x][y];//当前宝物价值
    long long ans = 0;
    //走到最后一格
    if (x == n - 1 && y == m - 1)
    {
        //手中宝物数等于k 或者 手中宝物数比k少1,并且当前格子宝物价值大于手中宝物价值的最大值,可以捡起最后一个宝物,同样符合条件。因此方案数+1
        if (cnt == k||(cnt==k-1&&cur>max))
        {
            ans++;
            if (ans > MOD)//取模操作
                ans = ans % MOD;
        }
        return ans;//返回方案数
    }
    //当前格子宝物价值大于手中宝物价值的最大值,并且拾起该宝物,将方案数叠加
    if (cur > max)
    {
        ans += dfs(x, y + 1, cur, cnt + 1);//向右
        ans += dfs(x + 1,y , cur, cnt + 1);//向下
    }
    //1. 当前当前格子宝物价值大于手中宝物价值的最大值,但不拾起
    //2. 当前当前格子宝物价值小于手中宝物价值的最大值
    ans += dfs(x, y + 1, max, cnt);//向右
    ans += dfs(x + 1, y, max, cnt);//向下
    //写入缓存
    cache[x][y][max+1][cnt] = ans % MOD;
    return cache[x][y][max+1][cnt];//返回方案数
}
int main()
{
    cin >> n >> m >> k;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            cin >> maze[i][j];
    memset(cache, -1, sizeof(cache));//初始化为-1
    cout<<dfs(0, 0, -1, 0)<<endl;
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值