问题描述
在蓝桥王国中,有 nnn 名士兵。对于第 iii 名士兵:
- 进行一次训练的成本为 pip_ipi 枚金币。
- 他至少需要进行 cic_ici 次训练才能成为顶尖战士。
王国推出了一种组团训练方案:
- 该方案包含每位士兵所需的一次训练。
- 购买一次组团训练方案的总成本为 SSS 枚金币。
- 组团训练方案可以多次购买。
目标是计算最少需要花费多少金币,才能让所有士兵都成为顶尖战士。
示例
输入:
n = 3(3 名士兵)
p = [1, 2, 3](每位士兵的训练成本)
c = [3, 2, 1](每位士兵需要的训练次数)
S = 4(组团训练方案的成本)
输出:6
解释:
购买 2 次组团训练方案,花费 2 * 4 = 8 枚金币。
但更优的方案是:
- 对第 1 名士兵单独训练 3 次,花费 3 * 1 = 3 枚金币。
- 对第 2 名士兵单独训练 2 次,花费 2 * 2 = 4 枚金币。
- 对第 3 名士兵单独训练 1 次,花费 1 * 3 = 3 枚金币。
总花费为 3 + 4 + 3 = 10 枚金币。
最优方案是混合使用组团训练和单独训练:
- 购买 1 次组团训练方案,花费 4 枚金币。
- 对第 1 名士兵单独训练 2 次,花费 2 * 1 = 2 枚金币。
- 总花费为 4 + 2 = 6 枚金币。
解题思路
这是一个典型的 组合优化问题,可以通过 动态规划 来解决。我们需要在组团训练和单独训练之间找到最优的组合,使得总成本最小。
关键点
- 组团训练的优势:
- 组团训练方案的成本为 S,包含每位士兵的一次训练。
- 如果组团训练方案的成本低于单独训练的总成本,则优先使用组团训练。
- 单独训练的优势:
- 如果某个士兵的训练成本较低,单独训练可能更划算。
- 动态规划状态定义:
- 设
dp[k]
表示购买k
次组团训练方案时的最小总成本。
- 设
- 状态转移:
- 对于每个士兵,计算在购买
k
次组团训练方案后,还需要单独训练的次数。 - 更新
dp[k]
的值。
- 对于每个士兵,计算在购买
动态规划解法
- 初始化:
- 计算每个士兵需要的额外训练次数:
extra[i] = max(0, c_i - k)
,其中k
是购买组团训练方案的次数。 - 计算单独训练的总成本:
sum(p_i * extra[i] for all i)
。
- 计算每个士兵需要的额外训练次数:
- 状态转移:
- 对于每个可能的
k
(从 0 到max(c_i)
),计算总成本:total_cost = k * S + sum(p_i * max(0, c_i - k))
。 - 找到最小的
total_cost
。
- 对于每个可能的
C++ 实现
以下是基于动态规划的 C++ 代码实现:
#include <vector>
#include <algorithm>
using namespace std;
int minCost(int n, vector<int>& p, vector<int>& c, int S) {
int max_k = *max_element(c.begin(), c.end()); // 最大需要的训练次数
int min_cost = INT_MAX; // 最小总成本
// 遍历可能的组团训练次数 k
for (int k = 0; k <= max_k; ++k) {
int total_cost = k * S; // 组团训练的成本
for (int i = 0; i < n; ++i) {
int extra = max(0, c[i] - k); // 需要单独训练的次数
total_cost += p[i] * extra; // 单独训练的成本
}
min_cost = min(min_cost, total_cost); // 更新最小总成本
}
return min_cost;
}
复杂度分析
- 时间复杂度:
- 外层循环遍历 kkk,最多 max(ci)max(c_i)max(ci) 次。
- 内层循环遍历 nnn 名士兵。
- 总时间复杂度为 O(n∗max(ci))O(n * max(c_i))O(n∗max(ci))。
- 空间复杂度:
- 只使用了常数级别的额外空间,空间复杂度为 O(1)O(1)O(1)。
总结
通过动态规划,我们可以高效地解决这个问题。关键在于遍历所有可能的组团训练次数 kkk,并计算对应的总成本。这种方法不仅适用于本题,还可以推广到类似的组合优化问题中。