动态规划(Dynamic Programming,DP)是解决背包问题的一种非常有效的方法。背包问题有多种变体,其中最经典的是0/1背包问题。下面我将详细解释动态规划在解决0/1背包问题中的应用细节。
0/1背包问题概述
给定一组物品,每个物品有一个重量和一个价值,以及一个背包的最大承载重量。目标是选择一些物品放入背包,使得总价值最大,但总重量不超过背包的最大承载重量。每个物品只能选择一次(要么选,要么不选)。
动态规划的基本思想
动态规划的核心思想是将复杂问题分解为子问题,通过解决子问题来逐步构建最终问题的解。在背包问题中,动态规划通过构建一个表格来记录每个子问题的最优解,从而逐步推导出整个问题的最优解。
动态规划的具体步骤
-
定义状态
- 用一个二维数组
dp[i][j]
表示前i
个物品在背包容量为j
时的最大价值。
- 用一个二维数组
-
状态转移方程
- 对于每个物品
i
(从1到n)和每个容量j
(从0到C),有两种选择:- 不选第
i
个物品:dp[i][j] = dp[i-1][j]
- 选第
i
个物品(前提是j
要大于等于第i
个物品的重量w[i]
):dp[i][j] = dp[i-1][j-w[i]] + v[i]
- 不选第
- 综合上述两种情况,状态转移方程为: [ dp[i][j] = \max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]) ]
- 其中,
w[i]
是第i
个物品的重量,v[i]
是第i
个物品的价值。
- 对于每个物品
-
初始化
dp[0][j] = 0
,表示没有物品时,无论背包容量多大,最大价值都是0。dp[i][0] = 0
,表示背包容量为0时,无论有多少物品,最大价值都是0。
-
填充DP表
- 按照状态转移方程,逐行逐列填充
dp
表。
- 按照状态转移方程,逐行逐列填充
-
获取结果
- 最终
dp[n][C]
即为问题的解,表示前n
个物品在背包容量为C
时的最大价值。
- 最终
代码示例(Python)
def knapsack(weights, values, capacity):
n = len(weights)
创建DP表
dp = [[0] * (capacity + 1) for _ in range(n + 1)]
# 填充DP表
for i in range(1, n + 1):
for j in range(1, capacity + 1):
if j >= weights[i-1]:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-weights[i-1]] + values[i-1])
else:
dp[i][j] = dp[i-1][j]
return dp[n][capacity]
示例数据
weights = [2, 3, 4, 5] values = [3, 4, 5, 6] capacity = 5
调用函数
max_value = knapsack(weights, values, capacity) print(f"最大价值为: {max_value}")
其他变体
- 完全背包问题:每个物品可以选多次。
- 状态转移方程:
dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]] + v[i])
- 状态转移方程:
- 多重背包问题:每个物品有数量限制。
- 可以通过二进制拆分转化为0/1背包问题。
发表回复