多重背包问题两种解法
c++
多重背包问题
/* * 多重背包问题 * 问题描述: * 有 N 种物品和一个容量是 V 的背包。 * 第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。(这样的话和 01 背包和完全背包都不一样) * 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 * 输出最大价值。 * * 数据范围: * 0 < N, V ≤ 100 * 0 < vi,wi,si ≤ 100 * 背包问题都是算法的经典题目,下面给出 多重背包问题 的解题思路: * * 解题思路1 朴素解法: * 数组定义: * f[i][j] 表示前 i 个物品,体积为小于等于 j 的最大价值 * 递归方程: * f[i][j] = max(f[i-1][j], f[i-1][j-vi]+wi, ..., f[i-1][j-kvi]+kwi k<=j//vi && k <= si) * 初始化结果: * f[0][0] = 0 * 最终结果 * max(f[n][0], f[n][1], ..., f[n][m]) * 复杂度分析: * 时间复杂度为 O(NMS) * * 解题思路2 多重背包转01背包 * 算法思路: * 因为朴素方法的多重背包复杂度过高 O(NMS) 考虑使用 01背包方法优化,思路主要从将 s_i 拆分入手 * 如 17 个物品,可以转换为 1个、2个、4个、8个、2个 的组合,他们的 01背包。 * 因为 任何小于等于 17 的东西,可以由 (1, 2, 4, 8, 2) 组合得到,任何大于 17 都不能被组合成功。 * * 拆分 x: * 首先重 1, 2, 4, 8 ... 一直到 x 无法被细分,剩余的 x 部分,再塞进去 * * x -> (1, 2, 4, 2 ^ k, x - (2 ^ (k + 1) - 1)),并且 x - (2 ^ (k + 1) - 1) <= 2 ^ (k + 1) * 而且从算法的角度来看 (1, 2, 4, 2 ^ k) 的组合,囊括了 [1, 2 ^ (k + 1) - 1] 的所有点。 * x - (2 ^ (k + 1) - 1) 起到的是平移区间左右,使得其可以 到达 x 的范围。 * * 因为拆出来的 n 数量稍多,建议使用空间优化的方案 * * 复杂度: * O(NMlogS) * */ #include <iostream> #include <cstring> #include <algorithm> #include <string> #include <cstdio> using namespace std; const int N = 1010, M = 2010; int n, m; int v[N], w[N], s[N]; int f[N][M]; int solution_one() { // initial memset(f, 0, sizeof f); // 递推方程 for (int i = 1; i <= n; i ++ ) { for (int j = 0; j <= m; j ++ ) { for (int k = 0; k <= s[i] && k <= j / v[i]; k ++ ) { f[i][j] = max(f[i][j], f[i-1][j-k*v[i]] + k*w[i]); } } } // 返回结果 return f[n][m]; } int solution_two() { int v01[N * 20], w01[N * 20]; int n1 = 0, k; // split to 01 for (int i = 1; i <= n; i ++ ) { k = 1; while (s[i] >= k) { s[i] -= k; n1 += 1; v01[n1] = v[i] * k; w01[n1] = w[i] * k; k *= 2; } if (s[i] != 0) { n1 += 1; v01[n1] = v[i] * s[i]; w01[n1] = w[i] * s[i]; } } int f[M]; memset(f, 0, sizeof f); for (int i = 1; i <= n1; i ++ ){ for (int j = m; j >= v01[i]; j -- ) { f[j] = max(f[j], f[j - v01[i]] + w01[i]); } } return f[m]; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i ++ ) { scanf("%d%d%d", &v[i], &w[i], &s[i]); } int res = solution_two(); printf("%d\n", res); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)