动态规划(Dynamic Programming,DP)是解决复杂优化问题的一种高效算法,核心思想是将问题分解为重叠子问题,通过记忆化存储避免重复计算。本文以经典的 **0-1背包问题** 为例,详细讲解如何在MATLAB中实现动态规划算法,并提供完整代码和解析。
输入:物品重量 `weights = [2, 3, 4, 5]`,物品价值 `values = [3, 4, 5, 6]`,背包容量 `capacity = 8`。
目标:在不超过背包容量的前提下,选择物品使得总价值最大。
输出:最大价值及所选物品列表。
---
1. 状态定义:
- 创建二维数组 `dp`,`dp(i,j)` 表示前 `i` 个物品在容量 `j` 时的最大价值。
2. 状态转移方程:
- 若当前物品重量 `weights(i) > j`,无法选择,`dp(i,j) = dp(i-1,j)`。
- 否则,比较选择与不选择该物品的价值:
`dp(i,j) = max(dp(i-1,j), dp(i-1,j-weights(i)) + values(i))`。
3. 初始化:
- `dp(0,:) = 0`(无物品时价值为0),`dp(:,1) = 0`(容量为0时价值为0)。
4. 回溯找最优解:
逆推 `dp` 数组,确定哪些物品被选中。
function [maxValue, selectedItems] = knapsackDP(weights, values, capacity)
n = length(weights);
dp = zeros(n+1, capacity+1); % 初始化DP表
% 填充DP表
for i = 1:n
for j = 1:capacity
if weights(i) > j
dp(i+1, j+1) = dp(i, j+1);
else
dp(i+1, j+1) = max(dp(i, j+1), dp(i, j+1 - weights(i)) + values(i));
end
end
end
maxValue = dp(n+1, capacity+1);
% 回溯找所选物品
selectedItems = zeros(1, n);
j = capacity;
for i = n:-1:1
if dp(i+1, j+1) ~= dp(i, j+1)
selectedItems(i) = 1;
j = j - weights(i);
end
end
end
weights = [2, 3, 4, 5];
values = [3, 4, 5, 6];
capacity = 8;
[maxVal, items] = knapsackDP(weights, values, capacity);
disp(['最大价值: ', num2str(maxVal)]);
disp('所选物品索引: ');
disp(find(items));
输出结果:
最大价值: 10
所选物品索引:
1 2 4
1. DP表构建:
- MATLAB索引从1开始,需将`dp`维度设为`(n+1)×(capacity+1)`。
- 内层循环遍历容量,外层遍历物品,避免重复计算。
2. 回溯机制:
- 从最后一个物品逆推,若当前物品被选中(`dp`值变化),则标记并减少剩余容量。
3. 复杂度分析:
- 时间复杂度:O(n×capacity),空间复杂度:O(n×capacity)。可通过滚动数组优化空间至O(capacity)。
---
动态规划通过存储中间结果显著提升效率,MATLAB的矩阵操作能高效实现DP表填充。本文代码可直接应用于其他背包问题变种(如完全背包)。对于大规模问题,建议结合剪枝或贪心策略进一步优化。