描述
有一个背包能装的重量maxw(正整数,0≤maxw≤20000),同时有n件物品(0≤n≤100),每件物品有一个重量wi(正整数)和一个价值pi(正整数)。要求从这n件物品中任取若干件装入背包内,使背包的物品价值最大。
输入描述
第1行:背包最大载重maxw,物品总数n
第2行到第n+1行:每个物品的重量和价值
输出描述
一个数字即背包内物品最大价值
用例输入 1
10 3 4 5 3 4 6 9
用例输出 1
14
来源
动态规划 背包问题
一、问题分析:0-1 背包问题
这是经典的0-1 背包问题,核心约束是:
- 每件物品只能选择 “装” 或 “不装”(不能拆分);
- 装入物品的总重量不能超过背包最大载重
maxw; - 目标是最大化装入物品的总价值。
由于maxw最大为 20000,n最大为 100,适合使用动态规划(DP) 中的 “滚动数组” 优化方案,既能保证时间复杂度,又能节省空间。
二、动态规划解法思路
1. 定义 DP 数组
设dp[j]表示:背包载重为j时,能装入的最大价值。
数组长度为maxw + 1(覆盖从 0 到maxw的所有载重情况)。
2. 初始化 DP 数组
- 初始时,
dp[0...maxw]均为 0:因为载重为 0 时无法装任何物品,价值为 0;其他载重初始状态也为 0(尚未选择物品)。
3. 状态转移方程
对于每件物品(重量w,价值p),从后向前遍历载重j(从maxw到w):
dp[j] = max(dp[j], dp[j - w] + p)
- 解释:
dp[j](更新前):不装当前物品时,载重j的最大价值;dp[j - w] + p:装当前物品时,载重j的价值(即 “载重j - w的最大价值” 加上当前物品价值);- 取两者最大值,更新
dp[j]为最优解。
4. 为什么从后向前遍历?
避免同一件物品被重复装入。如果从前向后遍历,dp[j - w]可能已包含当前物品的价值,导致多次选择同一物品(变成 “完全背包” 问题)。
三、C++ 代码实现
cpp
运行
#include <iostream>
#include <vector>
#include <algorithm> // 用于max函数
using namespace std;
int main() {
// 1. 读取输入
int maxw, n;
cin >> maxw >> n;
vector<int> weights(n); // 存储物品重量
vector<int> values(n); // 存储物品价值
for (int i = 0; i < n; ++i) {
cin >> weights[i] >> values[i];
}
// 2. 初始化DP数组:dp[j]表示载重j时的最大价值
vector<int> dp(maxw + 1, 0);
// 3. 遍历每件物品,更新DP数组
for (int i = 0; i < n; ++i) {
int w = weights[i]; // 当前物品重量
int p = values[i]; // 当前物品价值
// 从后向前遍历载重,避免重复装同一物品
for (int j = maxw; j >= w; --j) {
dp[j] = max(dp[j], dp[j - w] + p);
}
}
// 4. 输出结果:背包最大载重maxw对应的最大价值
cout << dp[maxw] << endl;
return 0;
}
四、代码运行示例(以用例输入 1 为例)
输入:
plaintext
10 3
4 5
3 4
6 9
执行过程:
- 初始化
dp[0...10] = [0,0,0,0,0,0,0,0,0,0,0]; - 处理第 1 件物品(w=4, p=5):
- 遍历 j=10→4,更新
dp[4]=5、dp[5]=5、...、dp[10]=5;
- 遍历 j=10→4,更新
- 处理第 2 件物品(w=3, p=4):
- 遍历 j=10→3,例如
dp[7] = max(5, dp[4]+4=9)→9,dp[10] = max(5, dp[7]+4=13)→13;
- 遍历 j=10→3,例如
- 处理第 3 件物品(w=6, p=9):
- 遍历 j=10→6,
dp[10] = max(13, dp[4]+9=14)→14;
- 遍历 j=10→6,
- 最终
dp[10] = 14,输出结果。
五、复杂度分析
- 时间复杂度:O (n × maxw)。n 为物品数(100),maxw 为最大载重(20000),总运算量约 2×10⁶,效率极高。
- 空间复杂度:O (maxw)。使用滚动数组优化后,空间从二维(n×maxw)降至一维(maxw+1),节省内存。
六、边界情况处理
- 当
maxw=0时:背包无法装任何物品,输出 0; - 当
n=0时:无物品可装,输出 0; - 当物品重量超过
maxw时:该物品无法装入,自动跳过。
以上代码已涵盖所有边界情况,无需额外特殊处理。
1677

被折叠的 条评论
为什么被折叠?



