题目描述(B2173 多重背包)
代码
#include<bits/stdc++.h>
using namespace std;
int x1[5005],x2[5005],x3[5005];
long long dp[5005][10005];
int main(){
int n,v;
cin>>n>>v;
for(int i=1;i<=n;i++){
cin>>x1[i]>>x2[i]>>x3[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=v;j++){
long long zd=0;
for(int k=0;k<=min(x3[i],j/x1[i]);k++){
long long jz=dp[i-1][j-k*x1[i]]+k*x2[i];
zd=max(jz,zd);
}
dp[i][j]=zd;
}
}
cout<<dp[n][v];
return 0;
}
代码讲解:
1. 变量定义与含义
x1[i]:第 i 种物品的体积(重量)。x2[i]:第 i 种物品的价值。x3[i]:第 i 种物品的最大可用数量(即物品 i 最多可以选多少个)。dp[i][j]:动态规划数组。表示只考虑前 i 种物品,在背包容量为 j 时,能获得的最大价值。n:物品种类数。v:背包总容量。
2. 输入部分
for(int i=1;i<=n;i++){
cin>>x1[i]>>x2[i]>>x3[i];
}
循环读入 n 种物品的信息:每种物品的体积、价值和最大数量。
3. 核心动态规划(三重循环)
for(int i=1;i<=n;i++){ // 枚举物品种类
for(int j=1;j<=v;j++){ // 枚举背包容量
long long zd=0; // 当前状态的最大价值,初始为0
for(int k=0;k<=min(x3[i],j/x1[i]);k++){ // 枚举当前物品选取的数量k
long long jz=dp[i-1][j-k*x1[i]]+k*x2[i]; // 状态转移
zd=max(jz,zd); // 取最大值
}
dp[i][j]=zd; // 记录最优解
}
}
状态转移方程:
dp[i][j] = max(dp[i-1][j - k * x1[i]] + k * x2[i]),其中 0 ≤ k ≤ min(x3[i], j / x1[i])
解释:
k表示当前第 i 种物品选取的数量。k的上限有两个约束:- 不能超过该物品的最大数量
x3[i]。 - 选取 k 个物品的总体积
k * x1[i]不能超过当前背包容量 j,即k ≤ j / x1[i]。
- 不能超过该物品的最大数量
dp[i-1][j - k * x1[i]]表示不选当前这 k 个物品 i 时,用前 i-1 种物品填充剩余容量j - k * x1[i]所能获得的最大价值。+ k * x2[i]表示加上当前选的 k 个物品 i 的价值。
5. 样例动态规划表(n=3, V=10)
根据输入样例:
- 物品1:体积 w1=3,价值 v1=4,数量 c1=2
- 物品2:体积 w2=4,价值 v2=5,数量 c2=3
- 物品3:体积 w3=2,价值 v3=3,数量 c3=4
背包容量 V=10。dp[i][j] 表示考虑前 i 种物品、容量为 j 时的最大价值。
初始化:dp[0][j] = 0(没有物品可选时价值为0)
物品1(i=1):
| j | k=0 | k=1 | k=2 | dp[1][j] |
|---|---|---|---|---|
| 0-2 | 0 | - | - | 0 |
| 3 | dp[0][3]=0 | dp[0][0]+4=4 | - | 4 |
| 4-5 | 0 | 4 | - | 4 |
| 6 | dp[0][6]=0 | dp[0][3]+4=4 | dp[0][0]+8=8 | 8 |
| 7-8 | 0 | 4 | 8 | 8 |
| 9 | dp[0][9]=0 | dp[0][6]+4=4 | dp[0][3]+8=8 | 8 |
| 10 | dp[0][10]=0 | dp[0][7]+4=4 | dp[0][4]+8=8 | 8 |
物品2(i=2):基于 dp[1][j] 计算
| j | k=0 | k=1 | k=2 | k=3 | dp[2][j] |
|---|---|---|---|---|---|
| 0-3 | dp[1][j] | - | - | - | dp[1][j] |
| 4 | dp[1][4]=4 | dp[1][0]+5=5 | - | - | 5 |
| 5 | dp[1][5]=4 | dp[1][1]+5=5 | - | - | 5 |
| 6 | dp[1][6]=8 | dp[1][2]+5=5 | dp[1][-2]无效 | - | 8 |
| 7 | dp[1][7]=8 | dp[1][3]+5=9 | dp[1][-1]无效 | - | 9 |
| 8 | dp[1][8]=8 | dp[1][4]+5=9 | dp[1][0]+10=10 | - | 10 |
| 9 | dp[1][9]=8 | dp[1][5]+5=9 | dp[1][1]+10=10 | dp[1][-3]无效 | 10 |
| 10 | dp[1][10]=8 | dp[1][6]+5=13 | dp[1][2]+10=10 | dp[1][-2]无效 | 13 |
物品3(i=3):基于 dp[2][j] 计算
| j | k=0 | k=1 | k=2 | k=3 | k=4 | dp[3][j] |
|---|---|---|---|---|---|---|
| 0-1 | dp[2][j] | - | - | - | - | dp[2][j] |
| 2 | dp[2][2]=0 | dp[2][0]+3=3 | - | - | - | 3 |
| 3 | dp[2][3]=4 | dp[2][1]+3=3 | dp[2][-1]无效 | - | - | 4 |
| 4 | dp[2][4]=5 | dp[2][2]+3=3 | dp[2][0]+6=6 | - | - | 6 |
| 5 | dp[2][5]=5 | dp[2][3]+3=7 | dp[2][1]+6=6 | dp[2][-1]无效 | - | 7 |
| 6 | dp[2][6]=8 | dp[2][4]+3=8 | dp[2][2]+6=6 | dp[2][0]+9=9 | - | 9 |
| 7 | dp[2][7]=9 | dp[2][5]+3=8 | dp[2][3]+6=10 | dp[2][1]+9=9 | dp[2][-1]无效 | 10 |
| 8 | dp[2][8]=10 | dp[2][6]+3=11 | dp[2][4]+6=11 | dp[2][2]+9=9 | dp[2][0]+12=12 | 12 |
| 9 | dp[2][9]=10 | dp[2][7]+3=12 | dp[2][5]+6=11 | dp[2][3]+9=13 | dp[2][1]+12=12 | 13 |
| 10 | dp[2][10]=13 | dp[2][8]+3=13 | dp[2][6]+6=14 | dp[2][4]+9=14 | dp[2][2]+12=12 | 14 |
最终结果:dp[3][10] = 14,与样例输出一致。最优方案为:物品1选2件(体积6,价值8),物品3选2件(体积4,价值6),总价值14。
4. 输出结果
cout<<dp[n][v];
输出考虑所有 n 种物品,背包容量为 v 时的最大价值,即问题的最终答案。

1784

被折叠的 条评论
为什么被折叠?



