📜  无界背包(允许重复物品)(1)

📅  最后修改于: 2023-12-03 15:40:08.591000             🧑  作者: Mango

无界背包(允许重复物品)

介绍

无界背包是背包问题的一个变种,即一个物品可以选择多次放入背包,与 0/1 背包、完全背包不同。在无界背包中,物品有一个重量和一个价值,背包有一个容量限制,要求选择物品的重量总和不超过背包的容量,每个物品可以选择无限次放入背包,使得放入背包的物品的价值总和最大。

算法思路

无界背包可以通过动态规划来解决,而动态规划又可以通过状态转移方程来实现。

首先,我们定义一个一维数组 $dp$,其中 $dp[i]$ 表示容量为 $i$ 的背包所能达到的最大价值。

对于每个物品 $j$,可以选择无限次放入背包。所以,我们可以遍历所有小于等于背包容量的子问题,对于每个子问题都选择物品 $j$ 放入背包,然后再求解剩余容量下的最大价值。由于物品可以无限次选择,所以在选完物品 $j$ 后还可以继续选择物品 $j$ 。

状态转移方程如下:

$dp[i] = max(dp[i], dp[i-weight[j]]+value[j])$

其中,$weight[j]$ 表示物品 $j$ 的重量,$value[j]$ 表示物品 $j$ 的价值。这个方程的意义是:当选择物品 $j$ 放入背包时,当前容量为 $i$ 的背包所能达到的最大价值等于两种方案中的最大值,一种是不选择该物品直接使用 $dp[i]$,递推式为 $dp[i]$;另一种是选择该物品,此时背包的容量需要减去其对应的重量,即 $i-weight[j]$,而当前价值应该添加上该物品的价值 $value[j]$,递推式为 $dp[i-weight[j]]+value[j]$。

重复执行这个状态转移方程,直到子问题的容量大于当前背包的容量为止。最终,$dp[capacity]$ 就代表了在背包容量为 $capacity$ 的情况下所能达到的最大价值。

代码实现

这是一个 Python 的无界背包解法的示例:

def unbounded_knapsack(capacity, weights, values):
    dp = [0] * (capacity+1)
    for i in range(1, capacity+1):
        for j in range(len(weights)):
            if weights[j] <= i:
                dp[i] = max(dp[i], dp[i - weights[j]] + values[j])
    return dp[capacity]

这是一个 C++ 的无界背包解法的示例:

int unboundedKnapsack(int capacity, vector<int>& weights, vector<int>& values) {
    vector<int> dp(capacity+1);
    for (int i = 1; i <= capacity; ++i) {
        for (int j = 0; j < weights.size(); ++j) {
            if (weights[j] <= i) {
                dp[i] = max(dp[i], dp[i - weights[j]] + values[j]);
            }
        }
    }
    return dp[capacity];
}

以上的示例中,无界背包的容量为 capacity,物品的重量和价值分别由 weightsvalues 表示。通过遍历所有子问题并应用状态转移方程,最终计算出了在背包容量为 capacity 的情况下所能达到的最大价值。