1 条题解
-
0
一、题目简述
有 个馒头,每个价格 ;有 种盒子,每种容量 和价格 ,每种盒子最多买一个。 你可以选一些盒子,把馒头装进去(每个盒子装不超过容量的任意数量),按馒头总价卖出。 利润 = 卖出总价 - 盒子总价,没装盒的馒头不算。 求最大利润。
二、解题思路
馒头价格不同,肯定优先卖最贵的。 先把馒头价格从大到小排序,并算出前缀和 表示前 个最贵馒头的总价。
问题变成:选一些盒子,使总容量至少为 ( 从 到 ),并让盒子总成本最小,利润就是 ,取最大值。
- 用背包求最小成本 设 表示总容量 恰好 为 的最小盒子总价()。 初始化 ,其余为无穷大。 对每个盒子(容量 ,价格 ),令有效容量 。 因为是 01 背包,我们从 向下循环 ,用旧 更新新容量:
新容量
这样就能把总容量超过 的情况也归结到 里。
-
转为至少容量 计算后缀最小值 ,表示总容量至少为 的最小成本。 如果 无穷大,说明无法装 个馒头。
-
计算答案 枚举 ,若 有限,则利润为 ,取最大值。 注意不买盒子时 利润为 。
三、代码实现
#include <bits/stdc++.h> #define int long long using namespace std; const int MAXM = 10005; const int INF = 1e18; int m, n; int p[MAXM]; int pre[MAXM]; int dp[MAXM]; signed main() { cin.tie(0)->ios::sync_with_stdio(false); cin >> m >> n; for (int i = 1; i <= m; ++i) cin >> p[i]; sort(p + 1, p + m + 1, greater<int>()); pre[0] = 0; for (int i = 1; i <= m; ++i) pre[i] = pre[i-1] + p[i]; for (int i = 0; i <= m; ++i) dp[i] = INF; dp[0] = 0; for (int j = 0; j < n; ++j) { int c, e; cin >> c >> e; c = min(c, m); for (int k = m; k >= 0; --k) { if (dp[k] == INF) continue; int t = min(k + c, m); dp[t] = min(dp[t], dp[k] + e); } } // 后缀最小值 for (int i = m-1; i >= 0; --i) { dp[i] = min(dp[i], dp[i+1]); } int ans = 0; for (int x = 0; x <= m; ++x) { if (dp[x] < INF) { ans = max(ans, pre[x] - dp[x]); } } cout << ans << "\n"; return 0; }
- 1
信息
- ID
- 9007
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者