首先是01背包(1):
【题目描述】有n个重量和价值分别是wi,vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。
限制条件:(PS限制条件不同,动态方程也不同)
1 <= n <= 100;
1 <= wi,vi <= 100;
1 <= W <= 10000;//此处W较大,而wi,vi较小
输入
n = 4
(w,v)={(2,3),(1,2)(3,4),(2,2)}
W = 5
输出
7(选择第0,1,3号物品)
【分析一】
dp[i+1][j]:从0到i这i+1个物品中选出总重量不超过j的物品时总价值的最大值
dp[0][j]=0;
| dp[i][j] (j<w[i];
dp[i+1][j]= |
| max(dp[i][j], dp[i][j-w[i]+v[i]}) (其他)。
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]);
}
【分析二】
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]);
}
01背包(2):
还记得我们前面的条件吗?在这里,要把限制条件换一下
1 <= n <= 100
1 <= wi <= 10^7
1 <= vi <= 100
1 <= W <= 10^9
【分析】
dp[i+1][j]:=前i个物品中挑选出价值总和为j时总质量的最小值(不存在时就是一个充分大的数值INF)
初始值
dp[0][0] = 0;
dp[0][j] = INF;
此外,前i个物品中挑选出机制总和为j时,有
前i-1个物品中挑选价值总和为j的部分
前i-1个物品中挑选价值总和为j-v[i]的部分,然后再选中第i个物品
这两种方法之一,所以就能得到
dp[i+1][j] = min(dp[i][j], dp[i][j-v[i] + w[i];
这一递推式。最终的答案就在应以=于令dp[n][j] <= W的最大的j。
int dp[MAX_N+1][MAX_N * MAX_V + 1];//dp数组
void solve(){
fill(dp[0], dp[0] + MAX_N * MAX_V +1, INF);//此处需自己写出代码
dp[0][0] = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < MAX_N * MAX_V; j++){
if(j < v[i]){
dp[i+1][j] = dp[i][j];
}else{
dp[i+1][j] = min(dp[i][j], dp[i][j-v[i]] + w[i]);
}
}
}
int res = 0;
for(int i = 0; i <= MAX_N * MAX_V; i++)
if(dp[n][i] <= W)
res = i;
printf("%d\n", res);
}
完全背包:
【题目描述】有n个重量和价值分别是wi,vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。在这里,每种物品可以挑选任意多件。
限制条件:
1<=n<=100
1<=wi,vi<=100
1<=W<=10000
输入
n = 3
(w, v) = {(3,4), (4,5), (2,3)}
W = 7
输出
10(0号物品选1个,2号物品选2个)
【分析一】
令dp[i+1][j]:=从前i种物品中挑选总重不超过j时总价值的最大值。
dp[0][j]=0;
| max{dp[i-k*w[i]] + k*v[i] | 0<=k;}
dp[i+1][j] = |
| max{dp[i][j-k*w[i]] + k*v[i] | 0<=k;}
void solve(){
for(int i = 0; i < n; i++){
for(int j = 0; j <= W; j++){
for(int k = 0; k*w[i] <= j; k++){
dp[i+1][j] = max(dp[i+1][j], dp[i][j-k*w[i]] + k*v[i]);
}
}
}
printf("%d\n", dp[n][W]);
}
【分析二】
void solve(){
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]);
}
}
printf("%d\n", dp[W]);
}