0-1 背包问题:给定 n 种物品和一个容量为 C 的背包,物品 i 的重量是 wi,其价值为 vi 。
问:应该如何选择装入背包的物品,使得装入背包中的物品的总价值最大?
递归解法,对每个物品是否装入背包进行搜索:
int n,w;
int w[maxn],v[maxn];
int rec(int i,int j){
if(i == n) return 0;
if(w[i] > j) return rec(i + 1,j);
else return max(rec(i + 1,j),rec(i + 1,j - w[i]) + v[i]);
}
void solve(){
printf("%d\n",rec(0,w));
}
记忆化搜索:
int dp[maxn][maxn];
int rec(int i,int j){
if(dp[i][j] >= 0) return dp[i][j];
int res;
if(i == n) res = 0;
if(w[i] > j) res = rec(i + 1,j);
else res = max(rec(i + 1,j),rec(i + 1,j - w[i]) + v[i]);
return dp[i][j] = res;
}
void solve(){
//memset 只能将数组初始化为 0 或 -1!!!
memset(dp,-1,sizeof(dp));
printf("%d\n",rec(0,w));
}
动态规划:
dp[i+1][j] : 从前 i 种物品中选出重量不超过 j 时总价值的最大值。
int dp[maxn][maxn];
void solve(){
for(int i = 0;i < n;i++){
for(int j = 0;j <= W;j++){
if(j < w[i]) dp[i+1][j] = dp[i][j];
else dp[i+1][j] = max(dp[i][j],dp[i][j-w[i]] + v[i]);
}
}
printf("%d\n",dp[n][W]);
}
空间优化:
int dp[maxn];
void solve(){
for(int i = 0;i < n;i++){
for(int j = W;j >= w[i];j--){
dp[j] = max(dp[j],dp[j-w[i]] + v[i]);
}
}
printf("%d\n",dp[W]);
}