2026.03.30
动态规划求解分为3个步骤:状态->阶段->决策, 最终得到新的状态。
1. 背包问题概念
背包问题指在一个有容积或重量限制的背包中放入物品,物品有体积、重量、价值等属性,要求在满足背包限制的情况下放置物品,使背包中物品的价值之和最大。根据物品限制条件的不同,背包问题可分为01背包、完全背包、多重背包、分组背包和混合背包等。
混合背包是01背包、完全背包、多重背包、分组背包这4种基本背包问题的混合模型。混合背包通常包括其他4种基本背包问题中的一种或若干种情况。
四种基本背包问题的区别:

01背包 :每种物品只有1个
完全背包:每种物品有无穷多个
分组背包:第i组有cᵢ个物品
多重背包:每种物品有cᵢ个
2. 01背包
给定n种物品,每种物品都有重量wi和价值vi,每种物品只有一个,背包容量为W。求解在不超过背包容量的情况下,将哪些物品放入背包,使背包中的物品价值之和最大。每种物品只有一个,要么不放入(0),要么放入(1),因此称之为01背包。
01背包怎么求解?
(1)确定状态
dp[i][j]表示前i种物品放入容量为j的背包中获得的最大价值。
(2)划分阶段
第i阶段处理第i种物品,第i-1阶段处理第i-1种物品。当处理第i种物品时,前i-1种物品已处理完毕,只需考虑第i-1阶段向第i阶段的转移。
就是说i-1阶段求解完毕,才可以处理第i阶段。也就是说在求解第i阶段的状态时前面的所有阶段的状态都已经处理完毕。

第i种物品放入背包有两种情况,要么放入,要么不放入。
-
分支1:
不放入背包
既然物品i不放入背包,那么问题转化为子问题“将前i−1种物品放入容量为j的背包中获得的最大价值”,最大价值为dp[i−1][j]。
-
分支2:
放入背包
如果将物品i放入背包,容量j中肯定是要加上当前物品i的价值v[i],加上物品i后容量只剩下j-w[i],那么问题转化为子问题“将前i−1种物品放入容量为j−w[i]的背包中获得的最大价值dp[i−1][j−w[i]]”,加上第i种物品的价值v[i],即dp[i−1][j−w[i]] + v[i]。

原问题转化为子问题:
1.原问题为dp[i][j]的状态,也就是第i阶段背包中放置物品的最大价值,
2.子问题为把i-1个物品放入背包中的最大价值,也就是状态dp[i-1][j-w[i]];
所以如果把物品i放入背包,那么背包中最大价值dp[i][j] = dp[i-1][j-w[i]] + v[i];
(3)决策选择
若背包容量不足,则不能放入,价值仍为前i-1种物品处理后的结果;若背包容量充足,则考察放入、不放入哪种情况获得的价值更大。最终状态为价值更大者的值。
情况1:dp[i][j] = dp[i−1][j], (容量约束:j<w[i])
情况2:dp[i][j] = max{dp[i−1][j], dp[i−1][j−w[i]]+v[i]}, (容量约束:j≥w[i])
在情况2中为什么要比较放入i的价值大还是不放入i的价值大呢?
因为放入前状态不是dp[i−1][j],而是dp[i−1][j−w[i]],dp[i−1][j−w[i]]不一定比dp[i−1][j]大,也就是说dp[i−1][j−w[i]] + v[i] 也并不一定比dp[i−1][j]大,所以需要进行比较。
(4)边界条件
dp[0][j]=0,i=0,j=0,…W(不放入物品,i=0背包中价值肯定是0)
dp[i][0]=0,i=0,…n,j=0(背包容量是0,背包中不能放入任何物品,价值肯定是0)
(5)求解目标
dp[n][W]
实例讲解1:求解背包最大价值
问题描述
有5个物品,背包的容量为10。求放入背包的最大价值。
物品重量与价值:
-
重量w[](物品1~5):2,5,4,2,3
-
价值 v[](物品1~5):6,3,5,4,6
题意理解:
状态转移方程:
情况1:dp[i][j] = dp[i−1][j],(j<w[i]时照抄上一行)
情况2:dp[i][j] = max{dp[i−1][j], dp[i−1][j−w[i]]+v[i]},(j≥w[i])
其中dp[i−1][j] (上一行同列),dp[i−1][j−w[i]]+v[i] (上一行 j−w[i] 列到 +v[i])

(动态规划过程中每一步的计算结果,最终 dp[n][w] = [5][10]=17为最大价值)
算法分析:时间复杂度为 O(nW),空间复杂度为 O(nW)。
代码示例:动态二维数组
/01dp_00_max_value_00.cc
// 有5个物品,背包的容量为10。求放入背包的最大价值。
// 物品重量与价值:
// 重量w[](物品1~5):2,5,4,2,3
// 价值v[](物品1~5):6,3,5,4,6
// 求解背包最大价值
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// int vol背包容量, const vector<int> w物品体积或重量, const vector<int> v物品价值
int GetMaxValue(int vol, const vector<int> w, const vector<int> v)
{
int n = w.size();
vector<vector<int>> dp(n + 1, vector<int>(vol + 1, 0));
// 第0列初始化,表示当容量为0时,不能放入任何物品,背包价值为0
// 其实这里可以不要,因为上文已经初始化,这里只是为了表示注意初始化的意思
for (int i = 0; i < n; ++i) {
dp[i][0] = 0;
}
// 第0行初始化,表示当放入物品为0,背包价值为0
// 其实这里可以不要,因为上文已经初始化,这里只是为了表示注意初始化的意思
for (int j = 0; j < n; ++j) {
dp[0][j] = 0;
}
// 动态规划
for (int i = 1; i <= n; ++i) {



8714

被折叠的 条评论
为什么被折叠?



