01背包问题四种可能解法
作者:互联网
c++
01 背包问题
/*
* 0, 1 背包问题
*
* 问题描述:
* 有 n 件物品和一个容量是 m 的背包。每件物品只能使用一次。
* 第 i 件物品的体积是 vi,价值是 wi。
* 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
* 输出最大价值。
*
*
* 动态规划求解:
* 动态规划掰开了说,就是使用记忆数组记录之前计算的数据结果,然后中间使用记忆数组来求解。
* 一下给出几种记忆数组策略,并给出他们的优劣性。
* 算法思路1:
* 数组定义:
* f[i][j] 表示仅选择前 i 个物品,体积为 j 的最大价值。
* 递归方程:
* f[i][j] = max(f[i-1][j], f[i-1][j-v[j]] + w[j]) // 如果 j - v[j] >= 0的话
* 初始化方法:
* memset(f, 0xcf, sizeof f) 注意这个是最小值 0xcf,因为我们求得是 max
* f[0][0] = 0
* 最终结果:
* max(f[n][0], ..., f[n][m])
* 复杂度:
* O(NM)
* tips:
* 空间复杂度可以优化到 O(M),使用滚动数组,或者是使用考虑这个数组的前后性
* for (int i = 1; i <= n; i ++ ) {
* for (int j = m; j >= v[i]; j ++ ) {
* f[j] = min(f[j], f[j - v[i]] + w[i]) // 这里的变量方式保证了 f[j - v[i]] 是来自于 i - 1 的
* }
* }
*
* 算法思路2:
* 数组定义:
* f[i][j] 表示仅选择前 i 个物品,体积小于等于 j 的最大价值。
* 递归方程:
* f[i][j] = max(f[i-1][j], f[i-1][j-v[j]] + w[j]) // 如果 j - v[j] >= 0的话
* 初始化方法:
* memset(f, 0, sizeof f)
* 最终结果:
* f[n][m]
* 复杂度:
* O(NM)
* tips:
* 同样是可以按照解决方案 1 进行空间优化。
*
* 算法思路3:
* 数组定义:
* f[i][j] 表示仅选择前 i 个物品,价值等于 j 的最小体积。
* 递归方程:
* f[i][j] = min(f[i-1][j], f[i-1][j-w[j]] + v[j]) // 如果 j - w[j] >= 0的话
* 初始化方法:
* memset(f, 0x3f, sizeof f)
* f[0][0] = 0
* 最终结果:
* 遍历所有的价值,找到 f[n][i] 中体积满足的最大 i
* 复杂度:
* O(NV), V 为 VALUE 的限度,因为本题最大 V = 1000 * 1000 因此,复杂度过高
* tips:
* 同样是可以按照解决方案 1 进行空间优化。
*
* 算法思路4:
* 数组定义:
* f[i][j] 表示仅选择前 i 个物品,价值大于等于 j 的最小体积。
* 递归方程:
* f[i][j] = min(f[i-1][j], f[i-1][j-w[j]] + v[j]) // 如果 j - w[j] >= 0的话
* f[i][j] = min(f[i-1][j], 0 + v[j]) // 如果 j - w[j] >= 0的话,相当于 f[i][j <= 0] = 0
* 初始化方法:
* memset(f, 0x3f, sizeof f)
* f[0][0] = 0
* 初始化乍一看和 算法思路4一样,但是其实不同,因为 第二维度 为负数是成立的
* 最终结果:
* 遍历所有的价值,找到 f[n][i] 中体积满足的最大 i。
* 但是借助其单调性,可以二分。
* 复杂度:
* O(NV), V 为 VALUE 的限度,因为本题最大 V = 1000 * 1000 因此,复杂度过高
* tips:
* 同样是可以按照解决方案 1 进行空间优化。
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int N = 1010, M = N;
const int INF = 0x3f3f3f3f, _INF = 0xcfcfcfcf;
int n, m;
int w[N], v[N]; // v for volumn, w for weight
int f[N][M];
// 解决方案 1
int solution_one() {
memset(f, 0xcf, sizeof f);
f[0][0] = 0;
for (int i = 1; i <= n; i ++ ) {
for (int j = 0; j <= m; j ++ ) {
if (j >= v[i]) {
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
} else {
f[i][j] = f[i - 1][j];
}
}
}
int res = _INF;
for (int i = 0; i <= m; i ++ ) {
res = max(res, f[n][i]);
}
return res;
}
// 解决方案 2
int solution_two() {
memset(f, 0, sizeof f);
for (int i = 1; i <= n; i ++ ) {
for (int j = 0; j <= m; j ++ ) {
if (j >= v[i]) {
f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);
} else {
f[i][j] = f[i - 1][j];
}
}
}
int res = f[n][m];
return res;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) {
scanf("%d%d", &v[i], &w[i]);
}
int res = _INF;
res = solution_two();
printf("%d\n", res);
return 0;
}
标签:01,int,max,背包,体积,数组,include,解法 来源: https://www.cnblogs.com/lucky-light/p/16435758.html