C++01背包问题

一、01背包

概念:

给你一个容量为C的背包,有n个物品。每个物体都有两个属性,即重量(w)和价值(v)。如果背包剩余容量大于此物品的重量,即可放入,同时产生这个物品的价值。
问:如何将物体放入背包才能使放入物体的总价值最大,同时输出这个值?

为何不用贪心?

证明:

看到这个问题,你可能会想到使用贪心,我来反驳一下:

01 背包中,物品只能完整选择,选择某物品会占用背包空间,可能导致无法选择其他更有价值的物品组合。此时,贪心算法的 “局部最优”可能会排斥掉更优的全局组合。

举个反例:
背包最大承重为5,有3个物品,物品如下:

物品重量价值性价比(≈)
A451.25
B341.33
C341.33

贪心(按单位价值排序): 先选择 B 或 C,无法容纳其他物品,总价值是4。

最优解:选择A,总价值为5。

科普:

有一种背包叫做分数背包问题,可以把某一种物品分割放入背包中,这时你就可以利用这种贪心方法。

dp做法:

1. 状态定义

设 dp[i][j] 表示:考虑前 i 个物品(编号从 1 到 i),且背包承重上限为 j 时,能获得的最大总价值

  • 其中,i 的范围是 0 ≤ i ≤ ni=0 表示无物品);
  • j 的范围是 0 ≤ j ≤ Cj=0 表示背包承重为 0)。
2. 初始化
  • 当 i=0(无物品)时,无论背包承重 j 多大,总价值均为 0,即 dp[0][j] = 00 ≤ j ≤ C)。
  • 当 j=0(背包承重为 0)时,无论考虑多少物品,总价值均为 0,即 dp[i][0] = 00 ≤ i ≤ n)。
3. 转移方程

对于第 i 个物品(重量 w[i],价值 v[i]),有两种选择:

  • 不放入:此时总价值与 “考虑前 i-1 个物品、承重 j” 的情况相同,即 dp[i][j] = dp[i-1][j]
  • 放入(需满足 j ≥ w[i]):此时总价值为 “前 i-1 个物品在承重 j - w[i] 时的最大价值” 加上当前物品的价值,即 dp[i][j] = dp[i-1][j - w[i]] + v[i]

因此,转移方程为:

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]);
4. 最终答案

考虑所有 n 个物品,且背包承重为 C 时的最大价值,即 dp[n][C]

5. 时间复杂度与空间复杂度
  • 时间复杂度O(n*C),其中 n 是物品数量,C 是背包最大承重。需遍历 n*C 个状态,每个状态的计算为 O(1)
  • 空间复杂度
    • 原始二维数组:O(n*C)(存储 n+1 行、C+1 列的状态)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值