C++ 用动态规划解决《T83.小S的货船租债问题》| 豆包MarsCode AI刷题

61 阅读3分钟

题目内容与要求

小S在码头租用货船,有Q种不同类型的货船可供选择。每种货船有固定的数量m[i]、租赁成本v[i]和最大载货量w[i]。小S希望在预算V元内,租用能够承载最大总货物的货船组合。每种货船的具体信息包括数量、租赁价格和载货量。需要计算在给定预算下,她能租用的货船的最大总载货量是多少。

输入:

  • 货船种类数Q。
  • 总预算V(单位:元)。
  • 每种货船的信息列表ships,其中每个元素是一个三元组[m[i], v[i], w[i]],分别表示第i种货船的数量、租赁价格和每艘货船的最大载货量。

输出:

  • 在预算范围内,所能租用的货船的最大总载货量。

思路解析

这个问题可以使用动态规划来解决。我们需要定义一个状态dp[j],它代表在预算为j时,能够达到的最大总载货量。对于每一种货船,我们可以考虑是否要租用以及租用多少艘。因此,我们可以通过遍历所有可能的情况,并更新我们的状态dp[j]来找到最优解。

具体步骤如下:

  1. 初始化动态规划数组dp,长度为V+1,初始值都设为0。
  2. 对于每一种货船,从后向前遍历所有的预算j,如果当前货船的成本不超过预算,则尝试租用该货船,并更新dp[j]的值。
  3. 返回dp[V]作为最终答案。

代码解释

int solution(int Q, int V, const vector<vector<int>>& ships) {
    // 创建一个带有虚拟船的二维向量
    vector<vector<int>> ships_with_dummy = {{}};
    ships_with_dummy.insert(ships_with_dummy.end(), ships.begin(), ships.end());
    
    // 初始化动态规划数组 f
    vector<int> dp(V + 1, 0);
    
    // 动态规划求解
    for (int i = 1; i <= Q; ++i) {
        for (int j = V; j >= ships_with_dummy[i][1]; --j) {
            for (int k = 1; k <= ships_with_dummy[i][0]; ++k) {
                if (k * ships_with_dummy[i][1] > j) break;
                dp[j] = max(dp[j], dp[j - k * ships_with_dummy[i][1]] + k * ships_with_dummy[i][2]);
            }
        }
    }
    return dp[V];
}

核心知识

  • 动态规划:动态规划是一种高效的算法设计技术,主要用于解决具有重叠子问题和最优子结构特征的问题。其核心思想是将复杂问题分解成一系列较小的子问题,并且通过存储这些子问题的解来避免重复计算,从而显著提高算法的效率,更有效地解决问题。
  • 状态转移方程:在本题中,状态转移方程是dp[j] = max(dp[j], dp[j - k * ships_with_dummy[i][1]] + k * ships_with_dummy[i][2]),表示在预算为j的情况下,可以选择不租用或租用一定数量的某种货船,并取两者中的较大值。

总结

这道题目考察了对动态规划的理解和应用能力。通过合理地设计状态和状态转移方程,我们能够在多项式时间内得到问题的最优解。这种思想广泛应用于许多优化问题中,如背包问题、最长公共子序列等。理解并掌握动态规划的基本概念和方法,对于提高算法设计和分析的能力非常有益。