返回

01 背包问题:揭开动态规划的奇妙奥秘

后端

01 背包问题,一个听起来朴实无华的问题,却蕴含着计算机科学中至关重要的动态规划思想。它不仅是众多算法竞赛和编程面试的宠儿,更是实际生活中优化决策的利器。

01 背包问题概述

01 背包问题如下:

有 n 件物品和一个最多能背重量为 w 的背包。每件物品的重量是 weight[i],得到的价值是 value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

为了解决这个问题,我们首先需要明确目标:在背包容量的限制下,如何选择物品,才能使装入背包的物品总价值最大。

动态规划的闪亮登场

动态规划(Dynamic Programming)是一种解决优化问题的强大方法。它通过将问题分解成一系列重叠子问题,并逐个解决这些子问题,最终得到问题的整体解决方案。

在 01 背包问题中,我们可以定义子问题为:对于背包容量为 j,物品集合为 S,如何选择物品装入背包,才能使装入背包的物品总价值最大?

解决子问题的过程,本质上就是枚举物品,并根据物品的重量和价值,决定是否将其装入背包。具体而言,我们可以使用如下状态转移方程:

f(j, S) = max{f(j, S - {i}), f(j - weight[i], S - {i}) + value[i]}

其中:

  • f(j, S) 表示背包容量为 j,物品集合为 S 时,装入背包的物品总价值最大值。
  • f(j, S - {i}) 表示背包容量为 j,物品集合为 S 去掉物品 i 时,装入背包的物品总价值最大值。
  • f(j - weight[i], S - {i}) + value[i] 表示背包容量为 j - weight[i],物品集合为 S 去掉物品 i 时,装入背包的物品总价值最大值,加上物品 i 的价值。

通过不断地计算子问题,最终可以得到整体问题的最优解。

Python 实现

def knapsack(weight, value, capacity):
    n = len(weight)
    dp = [[0] * (capacity + 1) for _ in range(n + 1)]

    for i in range(1, n + 1):
        for j in range(1, capacity + 1):
            if weight[i - 1] > j:
                dp[i][j] = dp[i - 1][j]
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1])

    return dp[n][capacity]


if __name__ == "__main__":
    weight = [1, 3, 4, 5]
    value = [1, 4, 5, 7]
    capacity = 7
    max_value = knapsack(weight, value, capacity)
    print(max_value)

结语

01 背包问题是一个经典的动态规划问题,它不仅是算法竞赛和编程面试的常见题目,也是实际生活中优化决策的利器。通过深入理解 01 背包问题的解题思路和算法实现,我们可以掌握动态规划的精髓,并将其应用到更广泛的问题中。