0-1背包指的当往背包里装物品是,要么装,要么不装,而不能装物品的一部分;
部分背包问题指的是可以装物品的一部分,而不必做出0-1的二分选择;
贪心算法的关键所在是(贪心选择性质和最优子结构);自上而下,一个一个的做出贪心选择,不断将问题规约到更小的子问题;
动态规划的关键所在是(重叠子问题和最优子结构);自下而上,每一步都要做出选择,但这些选择依赖于子问题的解;
题目:
总共有3件物品,背包可容纳5磅的东西,物品1重1磅价值60元,物品2重2磅,价值100元,物品3重3磅,价值为120元,怎么才能最大化背包所装物品的价值?
我们假设:c[i]是第i件物品的重量,w[i]是第i件物品的价值,f[i][j]表示背包总的重量为j时,可选物品为物品1~i,背包能获得的最大价值。
用动态规划解0-1背包问题,我么从最小子问题开始求解,直到达到原问题的规模。最小子问题,我们知道,当背包大小为0时,或者物品件数为0时,这时程序结束。所以,这些都是最小的子问题。下面来求出递推公式,并给出dp表(存储小问题的解,防止在计算大问题时带来的重复计算的时间开销)。
1、最终的递推公式如下:
根据递推公式填写的dp表格如下:
1、根据最小问题,我们进行逐个的状态转移。当物品个数为0时,那么获得的最大价值不论背包有多大,那么都为0,这就填写了第1行;同理,当背包的大小为0时,那么不论物品有多重,那么最终获得的价值为0,这就填写了第1列;
2、如果此时只放第1件物品,那么当背包的最大重量为1时,其获得的最大价值为60,同理,当为2,3...5时,均为60,因为只有一个物品;这就填写了第2行;
3、当要放2件物品时,我们要判断背包的大小是否能容纳的下2件物品;即第2件物品放还是不放。即有当j<c[2]时,那么表示物品2的大小大于背包的大小,肯定不能放,所以,当背包大小为1时,获得的最大价值为60,当背包的大小为2时,此时,因为物品2的大小等于背包的重量。此时,如果放物品2获得的价值和不放物品2获得的价值我们取最大值。同理,当背包大小为3时,到底放不放物品2?根据公式,如果不放,那么获得的最大值为60.如果放的话,因为此时背包重量为3,如果放的话最大为160;以下以此类推,最终将问题转化为:
1、如果不放第i件物品,则问题转化为前i-1件物品放入容量为j的背包中;
2、如果放入第i件物品,则问题转化为前i-1件放入剩余的容量为j-c[i]的背包中,此时能获得的最大价值为f[i-1][j-c]i]]+w[i]。
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int N = 3, V = 5;//N为物品数量,V为背包的容量
int c[4] = { 0, 1, 2, 3 };
int w[4] = { 0, 60, 100, 120 };
/* int **dp = new int *[N + 1];
for (int i = 0; i < N + 1; i++){
dp[i] = new int[V + 1];
}*/
int(*dp)[6] = new int[4][6];
//填dp表
for (int i = 1; i < N + 1; i++){
dp[i][0] = 0;
}
for (int j = 1; j < V + 1; j++){
dp[0][j] = 0;
}
dp[0][0] = 0;
for (int i = 1; i < N + 1;i++)
{
for (int j = 1; j < V + 1; j++){
if (j < c[j]){
dp[i][j] = dp[i - 1][j];
}
else{
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - c[i]] + w[i]);
}
}
}
int result = dp[3][5];
cout << result << endl;
// for (int i = 0; i < 4; i++){
// delete[]dp[i];
// }
delete []dp;
return 0;
}