完全背包问题总结(C++实现)

1. 问题描述

完全背包问题是动态规划中的经典问题之一。与01背包问题不同,完全背包问题中每种物品可以选择多次,即物品的数量是无限的。

问题形式:

  • 给定一个容量为 [V] 的背包和 [N] 种物品。
  • 每种物品有一个重量 [w_i] 和一个价值 [v_i]。
  • 目标是从这些物品中选择若干件放入背包,使得背包中物品的总重量不超过 [V],且总价值最大。

2. 动态规划解法

完全背包问题可以通过动态规划来解决,核心思想是状态转移方程。

状态定义:

  • 设 [dp[i][j]] 表示前 [i] 种物品放入容量为 [j] 的背包中所能获得的最大价值。

状态转移方程:

[ dp[i][j] = \max(dp[i-1][j], dp[i][j-w_i] + v_i) ]

  • [dp[i-1][j]]:不选择第 [i] 种物品。
  • [dp[i][j-w_i] + v_i]:选择第 [i] 种物品,并继续考虑是否再次选择。

空间优化:

可以将二维数组优化为一维数组,状态转移方程变为:
[ dp[j] = max(dp[j], dp[j-w_i] + v_i) ]
注意:遍历顺序需要从前往后,以确保每种物品可以被多次选择。

3. 示例

假设背包容量 [V = 10],物品重量 [weights = {2, 3, 4}],物品价值 [values = {3, 4, 5}],则调用 complete_knapsack(10, weights, values) 将返回最大价值 12。

1. 二维数组模板代码

二维数组的实现更直观,适合理解完全背包问题的动态规划过程。

int complete_knapsack_2d(int V, vector<int>& weights, vector<int>& values) {
    int n = weights.size();
    vector<vector<int>> dp(n + 1, vector<int>(V + 1, 0));  // 初始化二维dp数组

    for (int i = 1; i <= n; i++) {  // 遍历物品
        for (int j = 0; j <= V; j++) {  // 遍历背包容量
            if (j >= weights[i - 1]) {  // 如果当前容量可以放入物品
                dp[i][j] = max(dp[i - 1][j], dp[i][j - weights[i - 1]] + values[i - 1]);
            } else {  // 如果当前容量无法放入物品
                dp[i][j] = dp[i - 1][j];
            }
        }
    }

    return dp[n][V];
}

特点:

  • 使用二维数组 [dp[i][j]],表示前 [i] 种物品放入容量为 [j] 的背包中的最大价值。
  • 状态转移方程:[ dp[i][j] = \max(dp[i-1][j], dp[i][j-w_i] + v_i) ]。
  • 空间复杂度为 [O(N \times V)],适合初学者理解。

2. 一维数组模板代码

一维数组的实现是二维数组的空间优化版本,效率更高。

int complete_knapsack_1d(int V, vector<int>& weights, vector<int>& values) {
    int n = weights.size();
    vector<int> dp(V + 1, 0);  // 初始化一维dp数组

    for (int i = 0; i < n; i++) {  // 遍历物品
        for (int j = weights[i]; j <= V; j++) {  // 遍历背包容量
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i]);
        }
    }

    return dp[V];
}

特点:

  • 使用一维数组 [dp[j]],表示容量为 [j] 的背包中的最大价值。
  • 状态转移方程:[ dp[j] = \max(dp[j], dp[j-w_i] + v_i) ]。
  • 空间复杂度为 [O(V)],效率更高。

3. 对比总结

特性二维数组实现一维数组实现
空间复杂度[O(N * V)][O(V)]
代码复杂度较高较低
适用场景初学者理解动态规划过程实际应用,效率优先
状态转移方程[dp[i][j] = \max(dp[i-1][j], dp[i][j-w_i] + v_i)][dp[j] = \max(dp[j], dp[j-w_i] + v_i)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值