完全背包
特点
给定 n n n 种物品,每种物品都有重量 w i w_i wi 和价值 v i v_i vi ,其数量没有限制。
背包容量为 W W W ,求解在不超过背包容量的情况下如何放置物品,使背包中物品的价值之和最大。
状态表示
f [ i ] [ j ] f[i][j] f[i][j]:从前 i i i 个物品中选,且总体积不超过 j j j 的最大价值。
初始边界条件
f [ 0 ] [ i ] = 0 ( 0 ≤ i ≤ n ) f[0][i]=0\ (0 \le i \le n) f[0][i]=0 (0≤i≤n)
意思为,从前 0 个物品中选,总体积不超过 i i i 的最大价值。
因为没选任何一个物品所以最大价值为 0。
转移方程
j < v i j < v_i j<vi 时: f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j] = f[i-1][j] f[i][j]=f[i−1][j]
j ≥ v i j \ge v_i j≥vi 时: f [ i , j ] = m a x ( f [ i − 1 , j ] , f [ i , j − v i ] + w i ) f[i,j] = max(f[i-1,j],f[i,j-v_i]+w_i) f[i,j]=max(f[i−1,j],f[i,j−vi]+wi)
代码
时间复杂度: 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][j - v[i]] + w[i]);
}
}
一维(优化空间):
for (int i = 1; i <= n; i ++ ) {
for (int j = v[i]; j <= m; j ++ ) {
f[j] = max(f[j], f[j - v[i]] + w[i]);
}
}