01背包问题四种可能解法
2022/7/1 23:23:45
本文主要是介绍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背包问题四种可能解法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南