1. 背包问题基础:从暴力搜索到动态规划
背包问题作为动态规划领域的经典案例,困扰过无数算法学习者。我第一次接触这个问题时,花了整整三天才真正理解其精髓。让我们从一个具体例子开始:假设背包容量为4kg,现有三件物品:吉他(1kg,1500元)、音响(4kg,3000元)、笔记本电脑(3kg,2000元),如何选择才能使背包价值最大化?
1.1 暴力枚举的局限性
最直观的解法是尝试所有组合:
- 只带吉他:1500元
- 只带音响:3000元
- 只带笔记本:2000元
- 吉他+笔记本:3500元(最优解)
- 其他组合超重
当物品数量为n时,时间复杂度高达O(2ⁿ)。对于n=100的情况,计算量将达到惊人的1.26×10³⁰次操作——即使全球最快的超级计算机也需要数百万年才能完成。
1.2 动态规划的突破思路
动态规划通过两个关键观察解决这个问题:
- 最优子结构:当前最优解可以由子问题的最优解组合得到
- 重叠子问题:不同决策路径会重复访问相同的子问题
我们定义dp[i][w]表示前i个物品在容量w时的最大价值。这个二维表格将成为我们解决问题的核心工具。
关键理解:dp表格的每个单元格都代表一个子问题的解,我们通过填充这个表格自底向上构建最终解。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 二维DP解法深度解析
2.1 状态转移方程推导
对于每个物品i和容量w,我们面临两种选择:
- 不装入:价值保持为dp[i-1][w]
- 装入:价值变为dp[i-1][w-wt[i]] + val[i]
因此状态转移方程为:
python复制dp[i][w] = max(dp[i-1][w], dp[i-1][w-wt[i-1]] + val[i-1]) if w >= wt[i-1]
else dp[i-1][w]
注意wt和val的索引是i-1,因为列表从0开始计数。
2.2 完整实现与示例
python复制def knapsack_2d(W, wt, val):
n = len(wt)
dp = [[0]*(W+1) for _ in range(n+1)]
for i in range(1, n+1):
