先把每件物品的收益算成价格乘重要度,再按预算做一维 0/1 背包,维护不超过预算时的最大满意度。
OJ: luogu
题目 ID: P1060
难度:普及-
标签:动态规划01背包背包
创建: 2026-06-19 14:42
更新: 2026-10-07 10:45
后置题目
luogu P1734最大约数和B 的主解把 A 教的「内层容量倒序枚举、每件至多选一次」一维 0/1 背包原样搬用(main.cpp 的 for (j=s; j>=i; --j) dp[j]=max(dp[j],dp[j-i]+val[i])),只多加真约数和预处理这层题意翻译。luogu P1910L 国的战斗之间谍B 直接沿用 A 教的 0/1 背包“容量倒序枚举保证每件物品只用一次”这一步(B 的 main.cpp 两层循环都写成倒序,注释即“两维容量都倒序,保证每个间谍最多只选一次”),只是把单个预算容量扩成探查风险与工资两维费用,其余状态设计与转移形状不变。luogu P1855榨取kkksc03B 的 main.cpp 把 A 教的一维 dp 倒序容量循环原样扩成 dp[j][k] 的两重倒序,用同一「倒序保证每件物品只参与一次转移」的机制保证愿望不重复选,新增的只是金钱/时间第二维费用和价值恒为 1 的计数目标。luogu P1507NASA的食物计划B 的正式解就是把 A 教的 0/1 背包容量倒序枚举这一具体步骤照搬过来:main.cpp:22-23 外层枚举物品、内层对体积与质量两重倒序循环做 dp[j][l]=max(dp[j][l],dp[j-h][l-t]+k),只是把单个容量换成体积、质量两维并改求最大卡路里,难度增量为 +2 的普及/提高-,方向正确。
题意
给出总预算 N 和 m 件物品。
每件物品有:
- 价格
v - 重要度
w
如果买下它,就会贡献一份满意度:
v * w
要求在总花费不超过 N 的前提下,让满意度总和最大。每件物品最多买一次。
思路
一句话本质:把每件物品的"价值"算成价格 × 重要度,这道题就退化成一个标准 01 背包。
先看最直接的暴力:
py
import sys
data = list(map(int, sys.stdin.buffer.read().split()))
n, m = data[0], data[1]
items = []
idx = 2
for _ in range(m):
v, p = data[idx], data[idx + 1]
idx += 2
items.append((v, p))
best = 0
for mask in range(1 << m):
cost = 0
value = 0
for i in range(m):
if mask >> i & 1:
v, p = items[i]
cost += v
value += v * p
if cost <= n:
best = max(best, value)
print(best)brute.py 枚举所有
这个暴力为什么慢?
如果把暴力看成背包问题,它缺了什么?
暴力的每件物品就是一个 0/1 选择,总花费就是"重量",总满意度就是"价值"。但题目没有直接给出"价值"——它要求价格乘重要度。只要把
为什么一维就够,不需要记具体选了哪些物品?
因为背包只关心"当前总花费"和"当前总价值"这两个数字,过去的决策被压缩进这两个数字中,不需要记录完整选法。
怎么理解容量倒序?
设
- 不买:
不变 - 买:从
转移,加上价值
如果容量正序,同一件物品可能被重复使用;倒序保证每件物品只参与一次转移。最终答案就是
代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 30005;
int n, m;
// dp[j] 表示花费 j 元能获得的最大价值(价格 × 重要度)。
int dp[MAXN];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int v, p;
cin >> v >> p;
int w = v * p; // 价值 = 价格 × 重要度
// 0/1 背包倒序枚举。
for (int j = n; j >= v; j--) {
dp[j] = max(dp[j], dp[j - v] + w);
}
}
cout << dp[n] << '\n';
return 0;
}复杂度
- 时间复杂度:
- 空间复杂度:
总结
这题和普通 0/1 背包的区别只有一点:
- 价值不是直接输入,而是
价格 * 重要度
只要先把这一层题意翻译出来,后面的状态设计和转移就和标准模板完全一致了。
一图流解析
这张图把本题的建模、关键转移、实现检查和训练方法压缩到一页,适合读完正文后复盘。
