1. 背包问题概述:从生活场景到算法模型
背包问题(Knapsack Problem)是计算机科学中最经典的优化问题之一,也是动态规划算法的典型应用场景。想象你即将开始一次长途旅行,行李箱的容量有限,而你有许多想带的物品,每件物品都有不同的体积和价值。如何选择物品组合,才能在不超过行李箱容量的前提下,带走最大总价值的物品?这就是背包问题的现实原型。
在算法竞赛和实际工程中,背包问题有以下主要变种:
- 01背包:每件物品最多选一次(拿或不拿)
- 完全背包:每种物品可以选无限次
- 多重背包:每种物品有数量限制
- 分组背包:物品分组,每组只能选一件
- 二维费用背包:物品消耗两种资源(如体积和重量)
理解这些变种的解法差异,是掌握动态规划思想的重要里程碑。本文将从最基础的01背包开始,逐步深入各类背包问题的解法精髓。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 01背包问题详解
2.1 问题定义与状态设计
给定N件物品和一个容量为V的背包,第i件物品的体积为w[i],价值为v[i]。每件物品只能选择拿或不拿(不能分割),求在不超过背包容量的前提下能获得的最大价值。
动态规划的核心在于状态定义和状态转移。对于01背包,我们定义:
dp[i][j]:考虑前i件物品,背包容量为j时能获得的最大价值
这个二维状态的设计思路是:通过逐步考虑更多物品(i从1到N)和更大容量(j从0到V),最终dp[N][V]就是问题的解。
2.2 状态转移方程推导
对于第i件物品,我们有两种选择:
- 不选:则最大价值等于前i-1件物品在容量j时的最大价值,即
dp[i][j] = dp[i-1][j] - 选:需要保证当前容量j ≥ w[i],此时最大价值为前i-1件物品在容量j-w[i]时的最大价值加上v[i],即
dp[i][j] = dp[i-1][j-w[i]] + v[i]
综合两种情况,状态转移方程为:
python复制dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]) if j >= w[i]
else dp[i-1][j]
2.3 基础实现代码
python复制N, V = map(int, input().split())
dp = [[0] * (V + 1) for _ in range(N + 1)]
for i in range(1, N + 1):
w, v = map(int, input().split())
for j in range(V + 1):
if w > j:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w] + v)
print(dp[N]
