动态规划:01 背包
睡不醒的鲤鱼 2021-10-07 常用算法 动态规划
# 一、问题定义
有 件物品和一个容量是 的背包,第 件物品的体积是 ,价值是 。
每件物品只能使用一次。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。
# 二、算法思想
# 三、代码实战
# AcWing 0002
题目:01 背包问题
有 件物品和一个容量是 的背包,第 件物品的体积是 ,价值是 。
每件物品只能使用一次。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。
输入格式
第一行两个整数,,用空格隔开,分别表示物品数量和背包容积。
接下来有 行,每行两个整数 ,用空格隔开,分别表示第 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
输入样例:
4 5
1 2
2 4
3 4
4 5
输出样例:
8
解答代码:
朴素解法:二维存储。
#include <iostream>
using namespace std;
const int N = 1010;
int v[N], w[N];
int f[N][N];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> v[i] >> w[i];
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
f[i][j] = f[i - 1][j];
if (j >= v[i]) {
f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
}
}
cout << f[n][m] << endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
优化解法:滚动数组一维存储。
- 朴素解法中,第一维只用到了 和 的状态;
- 朴素解法中,第二维只用到了 的状态。
#include <iostream>
using namespace std;
const int N = 1010;
int v[N], w[N];
int f[N];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> v[i] >> w[i];
}
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]);
}
}
cout << f[m] << endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
注意
第二层 for 循环是从大到小的。
如果按朴素解法中的从小到大更新,那么由于 j - v[i]
是严格小于 j
的,则更新语句等价于 f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i])
,因此对 j
从大到小进行枚举,保证 f[j - v[i]] + w[i]
中记录的是 f[i - 1][j - v[i]] + w[i])
。