1 条题解
-
0
题解:任务分组最小费用问题
算法思路
本题是一个经典的任务分批问题,需要将任务序列分成若干批处理,最小化总费用。采用动态规划 + 斜率优化的方法高效求解。
1. 问题分析
设:
- :任务 的处理时间
- :任务 的费用系数
- :每批任务的启动时间
费用计算:
- 如果任务 到 在同一批,它们的完成时间相同
- 完成时间 = 启动时间 + 该批所有任务处理时间之和
- 每个任务的费用 = 完成时间 × 费用系数
2. 动态规划模型
令:
- :时间前缀和
- :费用系数前缀和
- :处理前 个任务的最小费用
状态转移方程:
$$f_i = \min_{0 \le j < i} \{ f_j + sumT_i \times (sumC_i - sumC_j) + s \times (sumC_n - sumC_j) \} $$3. 斜率优化
将转移方程整理为:
$$f_i = \min_{0 \le j < i} \{ f_j - (s + sumT_i) \times sumC_j \} + sumT_i \times sumC_i + s \times sumC_n $$设:
则问题转化为:
$$f_i = \min_{0 \le j < i} \{ Y_j - K_i \times X_j \} + constant $$这是一个典型的斜率优化问题,可以用凸包维护。
代码实现
#include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int N = 3e5 + 5; const LL INF64 = 1LL << 60; int n, s; int t[N], c[N]; LL f[N]; int main() { cin.tie(0)->sync_with_stdio(0); cin >> n >> s; for (int i = 1; i <= n; i++) { cin >> t[i] >> c[i]; t[i] += t[i-1]; // 时间前缀和 c[i] += c[i-1]; // 费用系数前缀和 } fill(f, f + n + 1, INF64); f[0] = 0; static int q[N]; // 单调队列(存储决策点) int top = 0; // 队列指针 for (int i = 1; i <= n; i++) { // 二分查找最优决策点 auto check = [&](int a, int b) { return f[b] - f[a] > 1LL * (s + t[i]) * (c[b] - c[a]); }; int l = 0, r = top - 1, j = q[top]; while (l <= r) { int mid = (l + r) >> 1; if (check(q[mid], q[mid + 1])) { j = q[mid]; r = mid - 1; } else { l = mid + 1; } } // 状态转移 f[i] = f[j] + 1LL * t[i] * (c[i] - c[j]) + 1LL * s * (c[n] - c[j]); // 维护凸包(删除不在下凸壳上的点) while (top > 0) { int a = q[top - 1], b = q[top]; // 检查斜率单调性 if (1LL * (f[b] - f[a]) * (c[i] - c[b]) >= 1LL * (f[i] - f[b]) * (c[b] - c[a])) { top--; } else { break; } } q[++top] = i; // 将当前点加入队列 } cout << f[n] << endl; return 0; }关键优化
1. 斜率优化原理
对于决策点 和 (),如果:
则 比 更优。通过维护一个下凸壳,可以快速找到最优决策点。
2. 凸包维护
- 使用单调队列维护候选决策点
- 新加入点时要删除破坏凸性的点
- 查询时在凸包上二分查找切点
3. 二分查找优化
由于斜率 单调递增,决策点也单调前进,可以用二分快速定位。
复杂度分析
- 时间复杂度:
- 每个点入队出队一次:
- 每次二分查找:
- 空间复杂度:
对于 的数据规模,该算法能够高效运行。
算法正确性
- 动态规划正确性:状态转移方程完整考虑了所有可能的分组方案
- 斜率优化正确性:利用凸包性质保证找到全局最优解
- 数值稳定性:使用 long long 防止整数溢出
这种动态规划 + 斜率优化的方法是处理此类分批问题的最优解法,广泛应用于生产调度、资源分配等领域。
- 1
信息
- ID
- 4246
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者