01 背包
有 $N$ 件物品和一个容量为 $V$ 的背包。放入第 $i$ 件物品耗费的费用是 $C_i$,得到的价值是 $W_i$。求解将哪些物品装入背包可使价值总和最大。即限定每个物品要么拿(1个)要么不拿(0个)。
用$f[n, C]$表示将$n$个物品放入容量为$C$的背包获得的最大收益,而第$i$个物品无非是拿与不拿, \(f[i,C] = max(f[i - 1, C], f[i - 1, C - W[i] + V[i])\)
第一种时间复杂度为$O(nC)$
int zero_one_knapsack(vector<int>& v, vector<int>& w, int n , int C){
//每个物品有w和v两种属性,总共有n个物品
//整个背包只能携带一定的物品 sum(w_i) <= C 求max(sum(v_i))
vector<vector<int>> dp(n, vector<int>(C + 1));
for(int i = 0 ; i < n ; i ++) dp[i][0] = 0;
for(int j = 1; j <= C ; j ++) {
if(j >= w[0]){
dp[0][j] = v[0];
}else
dp[0][j] = 0;
}
for(int i = 1; i < n ; i ++){
for(int j = 1; j <= C ; j ++){
if( j < w[i]){
dp[i][j] = dp[i - 1][j];
}else{
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);
}
}
}
return dp[n - 1][C];
}
空间压缩后
int zero_one_knapsack_opt(vector<int>& v, vector<int>& w, int n , int C) {
vector<int> f(C + 1);
for(int i = 0 ; i < n ; i++){
for(int j = C ; j >= w[i] ; j --){
f[j] = max(f[j], f[j - w[i]] + v[i]);
}
}
return f[C];
}
完全(无界)背包问题
如果不限定每种物品的数量,同一样物品想拿多少拿多少,则问题称为无界或完全背包问题。
\(f[i][j] = max(f[i - 1][j], f[i - 1][ j - k*w[i] ] + k * v[i])\) 这里,$0 <= kw[i] <= j$,此时复杂读就变为$O(nC * \sum (C / w[i]))$
多重(有界)背包问题
如果限定物品i最多只能拿$m[i]$个,则问题称为有界或多重背包问题。
\[f[i][j] = max{f[i - 1][j - k * w[i]] + k * v[i] | 0 <= k <= m[i]}\]