【动态规划】多重背包问题

题目描述(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 的上限有两个约束:
    1. 不能超过该物品的最大数量 x3[i]
    2. 选取 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)

jk=0k=1k=2dp[1][j]
0-20--0
3dp[0][3]=0dp[0][0]+4=4-4
4-504-4
6dp[0][6]=0dp[0][3]+4=4dp[0][0]+8=88
7-80488
9dp[0][9]=0dp[0][6]+4=4dp[0][3]+8=88
10dp[0][10]=0dp[0][7]+4=4dp[0][4]+8=88

物品2(i=2):基于 dp[1][j] 计算

jk=0k=1k=2k=3dp[2][j]
0-3dp[1][j]---dp[1][j]
4dp[1][4]=4dp[1][0]+5=5--5
5dp[1][5]=4dp[1][1]+5=5--5
6dp[1][6]=8dp[1][2]+5=5dp[1][-2]无效-8
7dp[1][7]=8dp[1][3]+5=9dp[1][-1]无效-9
8dp[1][8]=8dp[1][4]+5=9dp[1][0]+10=10-10
9dp[1][9]=8dp[1][5]+5=9dp[1][1]+10=10dp[1][-3]无效10
10dp[1][10]=8dp[1][6]+5=13dp[1][2]+10=10dp[1][-2]无效13

物品3(i=3):基于 dp[2][j] 计算

jk=0k=1k=2k=3k=4dp[3][j]
0-1dp[2][j]----dp[2][j]
2dp[2][2]=0dp[2][0]+3=3---3
3dp[2][3]=4dp[2][1]+3=3dp[2][-1]无效--4
4dp[2][4]=5dp[2][2]+3=3dp[2][0]+6=6--6
5dp[2][5]=5dp[2][3]+3=7dp[2][1]+6=6dp[2][-1]无效-7
6dp[2][6]=8dp[2][4]+3=8dp[2][2]+6=6dp[2][0]+9=9-9
7dp[2][7]=9dp[2][5]+3=8dp[2][3]+6=10dp[2][1]+9=9dp[2][-1]无效10
8dp[2][8]=10dp[2][6]+3=11dp[2][4]+6=11dp[2][2]+9=9dp[2][0]+12=1212
9dp[2][9]=10dp[2][7]+3=12dp[2][5]+6=11dp[2][3]+9=13dp[2][1]+12=1213
10dp[2][10]=13dp[2][8]+3=13dp[2][6]+6=14dp[2][4]+9=14dp[2][2]+12=1214

最终结果:dp[3][10] = 14,与样例输出一致。最优方案为:物品1选2件(体积6,价值8),物品3选2件(体积4,价值6),总价值14。

4. 输出结果
cout<<dp[n][v];

输出考虑所有 n 种物品,背包容量为 v 时的最大价值,即问题的最终答案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值