题目内容与要求
小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]来找到最优解。
具体步骤如下:
- 初始化动态规划数组dp,长度为V+1,初始值都设为0。
- 对于每一种货船,从后向前遍历所有的预算j,如果当前货船的成本不超过预算,则尝试租用该货船,并更新dp[j]的值。
- 返回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的情况下,可以选择不租用或租用一定数量的某种货船,并取两者中的较大值。
总结
这道题目考察了对动态规划的理解和应用能力。通过合理地设计状态和状态转移方程,我们能够在多项式时间内得到问题的最优解。这种思想广泛应用于许多优化问题中,如背包问题、最长公共子序列等。理解并掌握动态规划的基本概念和方法,对于提高算法设计和分析的能力非常有益。