01背包
特点
给定 n n n 种物品,每种物品都有重量 w i w_i wi 和价值 v i v_i vi ,每种物品都只有 一个。
另外,背包容量为 W W W 。
求解在不超过背包容量的情况下将哪些物品放入背包,才可以使背包中的物品价值之和最大。
每种物品只有一 个,要么不放入(0),要么放入(1),因此称之为01背包。
状态表示
f [ i ] [ j ] \large f[i] [j] f[i][j]:从前 i i i 个物品中选,且总体积不超过 j j j 的最大价值。
初始边界条件
f [ 0 ] [ i ] = 0 ( 0 ≤ i ≤ n ) \large f[0] [i]=0\ (0 \le i \le n) f[0][i]=0 (0≤i≤n)
意思为,从前 0 个物品中选,总体积不超过 i i i 的最大价值。
因为没选任何一个物品所以最大价值为 0。
转移方程
根据选或不选第 i − 1 i - 1 i−1 个物品作为区分。
j ≥ v i j \ge v_i j≥vi 时 : f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − v i ] + w i ) \large f[i][j] = max(f[i-1][j],f[i-1][j-v_i]+w_i) f[i][j]=max(f[i−1][j],f[i−1][j−vi]+wi)
j < v i j < v_i j<vi 时: f [ i , j ] = f [ i − 1 ] [ j ] \large f[i,j]=f[i-1][j] f[i,j]=f[i−1][j]
代码
时间复杂度: O ( n m ) O(nm) O(nm)
二维
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= m; j ++ ) {
f[i][j] = f[i - 1][j];
if (j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
}
一维
for (int i = 1; i <= n; i ++ ) {
for (int j = m; j >= v[i]; j -- ) { //注意倒序循环!
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
}