简单背包问题

本文通过分支限界法解决0/1背包问题。设有4个物体,重量与价值各异,背包容量有限。通过计算单位价值排序并利用分支限界法逐步筛选,最终找到最优装载方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0/1背包问题:设有4个物体,其重量分别为(4,7,5,3),价值为(40,42,25,12),背包容量W = 10.

 

将货物按单位重量价值排序得到:

 

 

体编号

单位重量(W)

单位价值(V)

价值/重量(V/W)

a

4

40

10

b

7

42

6

c

5

25

5

d

3

12

4

使用分支限界法求解:

1.初始界限的设定:
    如果只取A得到(1,0,0,0),获得的价值为40,可以作为下界,即db = 40.如果包内放置的都是A价值的物品,则ub = W*(Va/Wa)= 10*10 = 100 .所以初始界限为:[40,100]
2.界限函数的设定:
解空间树中第i层的每个节点都代表对物品1→i做出的特定选择.这个选择由从根节点到该节点的路径唯一确定:左分支表示装入某物品,右分支表示不装入该物品.对于第i层某个节点,设包中以装入物品重量为w,获得价值为v,则包中剩余W-w与剩余下的物品的最大单位重量价值Vi+1/Wi+1的积,于是得到限界函数:
Ub = v + (W-w)*(Vi+1/Wi+1)

 

背包图解

 

(1).根结点1,没有任何物品装包,包重和价值都为0,由限界函数算得1的目标函数值为100.
(2).将a装入包内,得包重4,包价值10,目标函数值为40+(10-4)*6 = 76,将结点2加入待处理表PT中;结点3没有将a加入,故其包重10,包价值0.目标函数值为10*6=60.将结点3加入PT中.
(3).在表PT中选取目标函数值取得极大的结点2优先进行搜索. 

(4).在结点4,将物品2装入背包,因此,背包的重量为11,不满足约束条件,将结点4丢弃;在结点5,没有将物品2装入背包,因此,背包重量和获得的价值与结点2相同,目标函数值为40+(10-4)*5=70,将结点5加入表PT中.
(5).在PT中选择目标函数值取得极大的结点5优先进行搜索.
(6).在结点6,装入物品3,包重为9,价值为65,目标函数价值为65+(10-9)*4=69,将结点6加入PT中;在结点7,没有将物品3装入背包,因此包重及价值与结点5相同,目标函数值为40+(10-4)*4=64,将结点6加入PT表中.

(7).在PT中选取目标函数值取得极大的结点6优先进行搜索.
(8).在结点8,将物品d装入背包,得到包重为12,不满足约束条件,将结点8丢弃;在结点9,没有将物品4装入背包,因此背包重量和获得的价值与结点6相同,目标函数值为65.
(9).由于结点9是叶子结点,同事结点9的目标函数值是PT中的极大值,所以结点9对应的解就是问题的最优解,搜索结束.

### Python实现考虑体积质量的简单背包问题 在解决简单背包问题时,可以使用动态规划方法来找到最优解。以下是针对物品具有体积 \( W \) 质量 \( V \),并受限于背包总容量的情况下的解决方案。 #### 动态规划的核心思路 定义二维数组 `dp[i][j]` 表示从前 \( i \) 个物品中选择,当背包剩余容量为 \( j \) 时的最大价值。状态转移方程如下: \[ dp[i][j] = \begin{cases} dp[i-1][j], & \text{if } w_i > j \\ \max(dp[i-1][j], dp[i-1][j-w_i]+v_i), & \text{otherwise} \end{cases} \] 其中: - \( w_i \): 物品 \( i \) 的体积; - \( v_i \): 物品 \( i \) 的价值; - \( j \): 当前背包剩余容量。 最终的结果存储在 `dp[n][C]` 中,\( n \) 是物品总数,\( C \) 是背包最大容量。 --- #### 完整代码实现 以下是一个完整的 Python 实现,用于求解带体积质量限制的简单背包问题: ```python def knapsack(items, capacity): """ 解决带有体积质量限制的简单背包问题 :param items: 列表 [(w1, v1), (w2, v2)...],分别代表每个物品的体积价值 :param capacity: 背包的最大容量 :return: 最大价值以及对应的物品组合 """ n = len(items) # 初始化 DP 数组 dp = [[0] * (capacity + 1) for _ in range(n + 1)] # 填充 DP 表格 for i in range(1, n + 1): weight, value = items[i - 1] for j in range(capacity + 1): if weight > j: dp[i][j] = dp[i - 1][j] else: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight] + value) # 寻找具体方案 result = [] total_value = dp[n][capacity] remaining_capacity = capacity for i in range(n, 0, -1): if dp[i][remaining_capacity] != dp[i - 1][remaining_capacity]: result.append(i - 1) # 添加当前物品索引到结果列表 remaining_capacity -= items[i - 1][0] return total_value, result # 测试数据 items = [(2, 3), (3, 4), (4, 5), (5, 8)] # 每个元组的第一个值为体积,第二个值为价值 capacity = 5 # 背包最大容量 total_value, selected_items = knapsack(items, capacity) print(f"最大价值: {total_value}") print(f"选中的物品索引: {selected_items}") ``` --- #### 输出解释 假设输入参数为: - `items = [(2, 3), (3, 4), (4, 5), (5, 8)]` - `capacity = 5` 运行程序后会得到输出: ``` 最大价值: 7 选中的物品索引: [1, 0] ``` 这表明选择了第 0 号第 1 号物品(从零开始计数),它们的总体积不超过背包容量,且总价值达到最大。 --- #### 复杂度分析 - 时间复杂度:\( O(n \times C) \),其中 \( n \) 是物品数量,\( C \) 是背包容量。 - 空间复杂度:\( O(n \times C) \)。可以通过优化降低空间复杂度至 \( O(C) \)[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丈八涯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值