1 条题解
-
0
题意理解
我们有 n 个物品,每个物品有:
- 重量 w
- 截止时间 d(必须在第 d 秒前购买)
- 购买一个物品需要 1 秒
我们要选择一些物品,使得可以按某种顺序在截止时间前购买。
方案比较规则:
- 买的物品数量多的更好
- 数量相同时,总重量小的更好
输出前 k 个最好的方案。
关键点
一个物品集合可行的条件是:如果我们买了 m 个物品,那么它们的截止时间必须足够大,能够安排在第 1 到 m 秒购买。
具体来说:将选中的物品按截止时间从小到大排序后,第 i 个物品的截止时间必须 ≥ i。
思路
我们可以用动态规划来解决:
- 先把所有物品按截止时间 d 从小到大排序
- 用 dp[j] 表示选 j 个物品的最小总重量
- 遍历每个物品,更新 dp 数组
- 最后收集所有可能的 (数量, 重量) 对,按题目要求排序,输出前 k 个
算法步骤
- 读入 n, k 和物品列表
- 按 d 从小到大排序物品
- 初始化 dp 数组,dp[0] = 0,其他为无穷大
- 对于每个物品 (w, d):
- 从后往前更新 dp 数组(避免重复选择)
- 对于 j 从 n 到 1:
- 如果 j ≤ d 且 dp[j-1] 不是无穷大:
- dp[j] = min(dp[j], dp[j-1] + w)
- 如果 j ≤ d 且 dp[j-1] 不是无穷大:
- 收集所有 dp[j] 不是无穷大的 (j, dp[j]) 对
- 按数量从大到小、重量从小到大排序
- 输出前 k 个,不足补 (0, 0)
代码实现
#include <iostream> #include <vector> #include <algorithm> #include <climits> using namespace std; int main() { int n, k; cin >> n >> k; vector<pair<int, int>> items(n); // (d, w) for (int i = 0; i < n; i++) { cin >> items[i].second >> items[i].first; } // 按截止时间排序 sort(items.begin(), items.end()); // dp[j] = 选j个物品的最小总重量 vector<long long> dp(n + 1, LLONG_MAX); dp[0] = 0; for (int i = 0; i < n; i++) { int w = items[i].second; int d = items[i].first; // 从后往前更新 for (int j = n; j >= 1; j--) { if (dp[j - 1] != LLONG_MAX && j <= d) { if (dp[j] > dp[j - 1] + w) { dp[j] = dp[j - 1] + w; } } } } // 收集所有方案 vector<pair<int, long long>> solutions; for (int j = n; j >= 0; j--) { if (dp[j] != LLONG_MAX) { solutions.push_back({j, dp[j]}); } } // 排序:数量多的在前,数量相同时重量小的在前 sort(solutions.begin(), solutions.end(), [](auto& a, auto& b) { if (a.first != b.first) return a.first > b.first; return a.second < b.second; }); // 输出前k个 for (int i = 0; i < k; i++) { if (i < solutions.size()) { cout << solutions[i].first << " " << solutions[i].second << "\n"; } else { cout << "0 0\n"; } } return 0; }
样例验证
样例1
输入:
3 1 1 1 1 1 1 3输出:
2 2解释:最多能买2个物品,最小重量是2。
样例2
输入:
4 3 1 1 10 1 2 3 10 3输出:
3 13 3 22 2 3解释:
- 买3个物品的最小重量是13(物品1,3,4)
- 买3个物品的次小重量是22(物品2,3,4)
- 买2个物品的最小重量是3(物品1,3)
样例3
输入:
2 4 1 1 2 2输出:
2 3 1 1 1 2 0 0解释:
- 买2个物品:重量3
- 买1个物品:重量1或2
- 买0个物品:重量0
复杂度分析
- 排序:O(n log n)
- DP:O(n²)
- 总复杂度:O(n²),对 n ≤ 2000 可行
这个解法能够正确求出前 k 个最优方案。
- 1
信息
- ID
- 4242
- 时间
- 5000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 8
- 已通过
- 1
- 上传者