这段代码实现了0-1 背包问题的动态规划解法,并且使用了滚动数组来优化空间复杂度。以下是代码的详细思路解析:
1. 问题背景
给定 n
个物品,每个物品有其体积 v[i]
和价值 w[i]
,以及一个容量为 m
的背包。目标是选择物品使得总价值最大,同时总容量不超过背包的容量。
2. 动态规划的概念
动态规划是一种常用的算法技巧,用于解决具有重叠子问题和最优子结构的问题。在 0-1 背包问题中,动态规划通过维护一个一维数组 f
来记录不同状态下的最大价值。
3. 代码逻辑解析
(1) 输入数据
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
用户输入物品数量
n
和背包容量m
。对于每个物品,输入其体积
v[i]
和价值w[i]
。
(2) 动态规划状态转移
for (int i = 1; i <= n; i++)
for (int j = m; j >= v[i]; j--)
f[j] = max(f[j], f[j - v[i]] + w[i]);
外层循环:
遍历每个物品,从第 1 个到第
n
个。
内层循环:
遍历背包的每个容量,从
m
到v[i]
(逆序遍历)。逆序遍历的原因是避免重复使用同一个物品。如果正序遍历,同一个物品可能会被多次使用,从而变成完全背包问题。
状态转移:
f[j]
表示在容量为j
的背包下的最大价值。不选择第
i
个物品:f[j]
保持不变。选择第
i
个物品:如果当前容量j
大于等于第i
个物品的体积v[i]
,则可以考虑选择第i
个物品,更新f[j]
为f[j - v[i]] + w[i]
,即在容量为j - v[i]
的背包下的最大价值加上第i
个物品的价值。
(3) 输出结果
cout << f[m] << endl;
输出最终的最大价值,即
f[m]
。
4. 代码效率分析
时间复杂度:
两层循环遍历所有物品和所有容量,时间复杂度为 O(n × m)。
空间复杂度:
使用了一个一维数组
f
,空间复杂度为 O(m)。
5. 示例运行
输入:
3 5
1 2
2 3
3 4
运行过程:
输入数据:
n = 3, m = 5
v = [1, 2, 3], w = [2, 3, 4]
动态规划状态转移:
初始化
f
数组为 0。对于第 1 个物品:
f[5] = max(f[5], f[4] + 2) = 2
f[4] = max(f[4], f[3] + 2) = 2
f[3] = max(f[3], f[2] + 2) = 2
f[2] = max(f[2], f[1] + 2) = 2
f[1] = max(f[1], f[0] + 2) = 2
对于第 2 个物品:
f[5] = max(f[5], f[3] + 3) = 5
f[4] = max(f[4], f[2] + 3) = 5
f[3] = max(f[3], f[1] + 3) = 5
f[2] = max(f[2], f[0] + 3) = 3
对于第 3 个物品:
f[5] = max(f[5], f[2] + 4) = 7
f[4] = max(f[4], f[1] + 4) = 6
f[3] = max(f[3], f[0] + 4) = 4
输出:
7
6. 总结
这段代码的核心思路是通过动态规划解决 0-1 背包问题,并使用滚动数组优化空间复杂度。通过维护一个一维数组 f
,记录不同状态下的最大价值,并通过状态转移方程更新最大价值,最终找到在给定背包容量下的最大价值。这种方法的时间复杂度为 O(n × m),空间复杂度为 O(m),适用于中等规模的 0-1 背包问题。
完整代码
#include<bits/stdc++.h>
using namespace std;
// 定义数组的最大长度
const int N = 1010;
// n 代表物品的数量,m 代表背包的容量
int n, m;
// v 数组用来存储每个物品的体积,w 数组用来存储每个物品的价值
int v[N], w[N];
// f 数组是一维数组,f[j] 表示背包容量为 j 时能获得的最大价值
int f[N];
int main()
{
// 输入物品的数量 n 和背包的容量 m
cin >> n >> m;
// 循环读入每个物品的体积和价值
for(int i = 1; i <= n; i ++) cin >> v[i] >> w[i];
// 动态规划过程,外层循环遍历每个物品
for(int i = 1; i <= n; i ++)
// 内层循环从背包的最大容量 m 开始,递减到当前物品的体积 v[i]
for(int j = m; j >= v[i]; j --)
// 比较不选择第 i 个物品和选择第 i 个物品两种情况下的最大价值
// 不选择第 i 个物品时,f[j] 保持不变
// 选择第 i 个物品时,价值为 f[j - v[i]] + w[i]
f[j] = max(f[j], f[j - v[i]] + w[i]);
// 输出背包容量为 m 时能获得的最大价值
cout << f[m] << endl;
return 0;
}