dp分组背包

先看一道例题:

洛谷P1757通天之分组背包

题目描述

01 01 01 背包问世之后,小 A 对此深感兴趣。一天,小 A 去远游,却发现他的背包不同于 01 01 01 背包,他的物品大致可分为 k k k 组,每组中的物品相互冲突,现在,他想知道最大的利用价值是多少。

输入格式

两个数 m , n m,n m,n,表示一共有 n n n 件物品,总重量为 m m m

接下来 n n n 行,每行 3 3 3 个数 a i , b i , c i a_i,b_i,c_i ai,bi,ci,表示物品的重量,利用价值,所属组数。

输出格式

一个数,最大的利用价值。

样例 #1

样例输入 #1

45 3
10 10 1
10 5 1
50 400 2

样例输出 #1

10

提示

1 ≤ m , n ≤ 1000 1 \leq m, n \leq 1000 1m,n1000 1 ≤ k ≤ 100 1\leq k\leq 100 1k100 a i , b i , c i a_i, b_i, c_i ai,bi,ciint 范围内。
这种题怎么想呢?其实是从「在所有物品中选择一件」变成了「从当前组中选择一件」,于是就对每一组进行一次 0-1 背包就可以了。

再说一说如何进行存储。我们可以将 t(k,i) 表示第 k 组的第 i 件物品的编号是多少,再用 cnt (k) 表示第 k 组物品有多少个。

C++代码实现

for (int k = 1; k <= ts; k++)           // 循环每一组
  for (int i = m; i >= 0; i--) // 循环背包容量
    for (int j = 1; j <= cnt[k]; j++)   // 循环该组的每一个物品
      if (i >= w[t[k][j]])  // 背包容量充足
        dp[i] = max(dp[i], dp[i - w[t[k][j]]] + c[t[k][j]]);  // 像0-1背包一样状态转移

这里要注意:一定不能 搞错循环顺序,这样才能保证正确性。
下一章讲有依赖的背包。
在这里插入图片描述

### C语言实现分组背包问题 分组背包问题是背包问题的一种变体,其中每组物品有多个选项,但只能从中选择一件。其核心思想仍然是通过动态规划来解决。 #### 动态规划的状态转移方程 设 `f[i][j]` 表示从前 `i` 组物品中选取若干件放入容量为 `j` 的背包所能获得的最大价值,则状态转移方程如下: - 如果不选第 `i` 组中的任何物品: \[ f[i][j] = f[i-1][j] \] - 如果选择第 `i` 组中的某件物品 `k`(假设该物品的价值为 `w[k]`,体积为 `v[k]`),则: \[ f[i][j] = \max(f[i][j], f[i-1][j-v[k]] + w[k]) \] 最终的结果存储在 `f[n][W]` 中,即从所有组中选出总重量不超过 `W` 的最大价值组合[^4]。 --- #### 示例代码 以下是一个完整的 C 语言实现分组背包问题的代码示例: ```c #include <stdio.h> #include <string.h> #define MAX(a, b) ((a) > (b) ? (a) : (b)) int main() { int n = 3; // 组数 int W = 8; // 背包容量 // 每组物品的数量及其对应的体积和价值 int group_sizes[] = {2, 2, 3}; int volumes[][3] = {{0, 2, 3}, {0, 1, 6}, {0, 5, 4, 3}}; int values[][3] = {{0, 2, 4}, {0, 3, 5}, {0, 9, 7, 6}}; int dp[W + 1]; memset(dp, 0, sizeof(dp)); for (int i = 1; i <= n; ++i) { for (int j = W; j >= 0; --j) { for (int k = 1; k <= group_sizes[i - 1]; ++k) { if (j >= volumes[i - 1][k]) { dp[j] = MAX(dp[j], dp[j - volumes[i - 1][k]] + values[i - 1][k]); } } } } printf("The maximum value is: %d\n", dp[W]); return 0; } ``` --- #### 代码说明 1. **输入参数初始化**: - `n`: 总共有多少组物品。 - `W`: 背包的最大承重能力。 - `group_sizes`: 每一组中有多少种不同的物品。 - `volumes`: 各组物品的体积数组。 - `values`: 各组物品对应的价值数组。 2. **动态规划表构建**: 使用一维数组 `dp[j]` 来记录当前状态下背包容量为 `j` 时能够达到的最大价值。外层循环遍历每一组物品,内层循环逆序更新背包容量下的最优解。 3. **时间复杂度分析**: 假设有 `G` 组物品,总共 `N` 种物品,背包容量为 `W`,则时间复杂度为 \(O(G \times N \times W)\)[^4]。 4. **空间复杂度优化**: 利用滚动数组技术将二维 DP 数组压缩成一维数组,从而降低空间开销至 \(O(W)\)。 --- ### 注意事项 - 在实际应用中,需确保各组物品的数据范围合理,防止因越界访问而导致运行错误。 - 当数据规模较大时,可尝试进一步优化算法性能,例如剪枝或采用近似方法求解[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值