01背包
1.记忆化搜索+dfs
//记忆化搜索+dfs
int rec(int i, int j) {
if (dp[i][j] >= 0)//已经计算过的就可以使用之前的值
return dp[i][j];
int res;
if (i == n)res = 0;//0-n-1,第n个当然不能放了
else if (j < w[i])res = rec(i + 1, j)//不能放的时候第i个最大价值等于i+1的
else res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]);
return dp[i][j] = res;//记忆化
}
2.dp[i][j]为从第i个物品开始挑选总重小于j时,总价值的大小
物品从0-n-1编号
dp[n][j]=0;
dp[i][j]= dp[i+1][j](j< w[i])
dp[i][j]= max(dp[i+1][j],dp[i+1][j-w[i]]+v[i])(其他)
要求i必须先求出i+1,所以i是逆序
for(int i=n-1;i>=0;i--)
for (int j = 0; j <= w; 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]);
}
cout << dp[0][w] << endl;
3.dp[i+1][j]:从前i个物品中选出总重量不超过j的物品时总价值的最大值
dp[1][j]=dp[0][j]=0;
dp[i+1][j]=dp[i][j];
dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i])
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]);
}
}
cout << dp[n][w];
4.滚动数组优化空间(常用)
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]);
}
}
cout << dp[n] << endl;
完全背包
原理:
dp[i+1][j]的计算中选k个的情况,与在dp[i+1][j-w[i]]中的k-1个情况完全相同,所以dp[i+1][j]可由dp[i+1][j-w[i]]的计算得到
max{dp[i][j-k*w[i]]+kv[i]|0<=k}
=max(dp[i][j],max{dp[i][j-k*w[i]]+kv[i]|k>=1})
=max(dp[i][j],max{dp[i][j-w[i]-k*w[i]]+k*v[i]|k>=0}+v[i])
=max(dp[i][j],dp[i+1][j-w[i]]+v[i])
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 + 1][j - w[i]] + v[i]);
}
}
cout << dp[n][w];
滚动数组优化
for (int i = 0; i < n; i++) {
for (int j = w[i]; j <= w; j++) {
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}
}
cout<<dp[w];