【华为机考真题】动态规划之遗迹探险家小红(含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] 保持不变。
  • 当剩余资源 jk 允许时,我们可以选择拿,拿了之后需要判断是普通宝藏还是重型宝藏:
    • 普通宝藏t_i <= 30dp[j][k] = max(dp[j][k], dp[j - t_i][k] + p_i)
    • 重型宝藏t_i > 30dp[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. 几类动态规划问题方法梳理

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

相关推荐
万法若空19 小时前
C++ <memory> 库全方位详解
开发语言·c++
代码中介商20 小时前
C++ 类型转换深度解析:static_cast、dynamic_cast、const_cast、reinterpret_cast
开发语言·c++
青小莫20 小时前
C++之string(OJ练习)
开发语言·c++·stl
6Hzlia20 小时前
【Hot 100 刷题计划】 LeetCode 199. 二叉树的右视图 | C++ DFS 逆序遍历
c++·leetcode·深度优先
-Marks-20 小时前
【C++编程】STL简介 --- (是什么 | 版本发展历程 | 六大组件 | 重要性缺陷以及如何学习)
开发语言·c++·学习·stl·stl版本
CoderCodingNo21 小时前
【信奥业余科普】C++ 的奇妙之旅 | 12:程序的交互与加工——数据的输入与算术运算
开发语言·c++
yx868xy21 小时前
Cuda加速直线拟合
c++·cuda
蜗牛在听雨21 小时前
基于 C++ 的 UG/NX 二次开发环境配置
c++·二次开发·ug
SimpleLearingAI1 天前
C++虚函数详解
开发语言·c++