【华为机考真题】动态规划之遗迹探险家小红(含C++源码)

0. 前言

本文要介绍的一道题是动态规划的经典变种------二维费用背包问题,这是华为机考的第三题,也就是压轴题,有一定难度,下面我们进入正题。

1. 题目描述

小红在遗迹中收集宝藏。

遗迹中共有 n 件宝藏,收集第 i 件宝藏需要花费的时间为 t_i,价值为 p_i。

总探险时间不能超过 T,若 t_i > 30,则视为重型宝藏,重型宝藏的总数不得超过 m 个,并且每件宝藏只能收集一次。

满足上面限制的条件下,求小红能获得的最大价值总和。

输入和输出描述如下:

输出:一个整数,表示小红能获得的最大总价值。

2. 题目分析

在上一篇的幻兽防御战中,可以靠 排序+贪心 轻松解决。但在本题中:

  • 重型宝藏虽然价值高,但是它会占用重型宝藏的名额,并且耗时往往更长。
  • 选择了一个重型宝藏,可能会导致无法选择后面更优的两个普通宝藏的组合。
  • 当存在 互斥的多种约束 时,局部最优不等于全局最优,这时我们需要 穷举所有状态并记录最优解 ,这正是 动态规划 存在的意义。

3. 动态规划思路分析

3.1 确定dp数组的含义

本题中存在两个限制,分别是总时间 T 和重型宝藏名额 m。

我们定义:dp[j][k] 代表在剩余时间为 j,剩余重型名额为 k 时,能获得的最大价值。

3.2 确定状态转移方程

对于每一件宝藏,我们需要选择拿还是不拿。

  • 如果不拿,那么 dp[j][k] 保持不变。
  • 当剩余资源 j 和 k 允许时,我们可以选择拿,拿了之后需要判断是普通宝藏还是重型宝藏:
    • 普通宝藏 :t_i <= 30,dp[j][k] = max(dp[j][k], dp[j - t_i][k] + p_i)。
    • 重型宝藏 :t_i > 30,dp[j][k] = max(dp[j][k], dp[j - t_i][k - 1] + p_i)

3.3 其他需要注意的点

所有的 dp[j][k] 初始化为 0,代表初始状态下没有收集任何宝藏。

为了保证每件宝藏只被收集一次,内层循环(时间 j 和名额 k)必须采用 逆序 遍历。

按照这个思路,每一轮循环都会基于上一轮的结果更新当前的最高价值。

4. 代码实现

完整代码如下:

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>
#include <sstream>

using namespace std;

int main() {
    string line;
    getline(cin, line);
    stringstream ss(line);
    int n,T,m;

    ss >> n >>T >> m;

    vector<vector<int>> dp(T+1, vector<int> (m+1, 0));

    for(int i=0; i<n; i++)
    {
        int t_i,p_i;
        getline(cin, line);
        stringstream ss1(line);
        ss1 >> t_i >> p_i;//读到每件宝藏的时间和价值

        if(t_i > 30)//重型宝藏
        {
            for(int j=T; j>=t_i; j--)
            {
                for(int k=m; k>=1; k--)
                {
                    dp[j][k] = max(dp[j][k], dp[j-t_i][k-1]+p_i);
                }
            }
        }
        else 
        {
            for(int j=T; j>=t_i; j--)
            {
                for(int k=m; k>=0; k--)
                {
                    dp[j][k] = max(dp[j][k], dp[j-t_i][k]+p_i);
                }
            }
        }
    }
    cout << dp[T][m];
    return 0;
}

5. 几类动态规划问题方法梳理

我将常见的几类动态规划问题整理成下面的表格:

相关推荐
青少儿编程课堂10 分钟前
背包问题(0/1 背包与完全背包)解题精讲——动态规划入门
c++·python·算法·bfs·信息学竞赛
倒头就睡的小比特21 分钟前
C++多态
c++
潼心1412o3 小时前
C++初阶(长期更新)第5讲:类和对象(中)
开发语言·c++
weixin_307779133 小时前
C++代码实现MATLAB中的normalize函数功能
开发语言·c++·算法·matlab
(Charon)3 小时前
【C++面试】手写String类:同时实现拷贝构造与移动构造
c++·算法
程序员老陆3 小时前
通过std::unique_ptr初始化std::shared_ptr
开发语言·c++
Fate_I_C4 小时前
Capacitor 插件鸿蒙化实战:@capacitor/device 从安装到模拟器验证全记录
华为·harmonyos
西西弗Sisyphus5 小时前
Qt6 实现 会动的界面像物理世界一样
c++·qt
UIU1145 小时前
头文件可以防什么错?运用头文件做声明
c++·学习·c#
by209996 小时前
list:迭代器与资源管理实现的综合叙述(下)
数据结构·c++·笔记·list