首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

【算法】动态规划专题⑦ —— 多重背包问题 + 二进制分解优化 python

  • 25-02-16 13:21
  • 4498
  • 11607
blog.csdn.net

目录

  • 前置知识
  • 进入正题
  • 优化方法:二进制分解
  • 实战演练


前置知识


【算法】动态规划专题⑤ —— 0-1背包问题 + 滚动数组优化 python
【算法】动态规划专题⑥ —— 完全背包问题 python


进入正题


多重背包问题I https://www.acwing.com/problem/content/4/


题目描述

有 N N N 种物品和一个容量是 V V V 的背包。
第 i i i 种物品最多有 s i s_i si​ 件,每件体积是 v i v_i vi​,价值是 w i w_i wi​。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。

输入格式

第一行两个整数, N , V N,V N,V,用空格隔开,分别表示物品种数和背包容积。
接下来 N N N 行,每行三个整数 v i , w i , s i v_i, w_i, s_i vi​,wi​,si​,用空格隔开,分别表示第 i i i 种物品的体积、价值和数量。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N , V ≤ 100 0 \lt N, V \le 100 0<N,V≤100
0 < v i , w i , s i ≤ 100 0 \lt v_i, w_i, s_i \le 100 0<vi​,wi​,si​≤100

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2
  • 1
  • 2
  • 3
  • 4
  • 5

输出样例:

10
  • 1

在多重背包问题中,对于每种物品,你不仅可以选择是否放入背包,而且对于每种物品还有一个限制,即该物品最多可以放入的数量。
与0/1背包和完全背包不同:我们需要对每个物品的数量限制进行处理。

基本实现:

n, v = map(int, i
nput().split())
dp = [[0] * (v + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
    vi, wi, si = map(int, input().split())
    for j in range(1, v + 1):
        for k in range(min(si, j // vi) + 1):
            dp[i][j] = max(dp[i][j], dp[i - 1][j - k * vi] + k * wi)
print(dp[n][v])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

时间复杂度为O(n*v*s),有没有优化的方法呢?


优化方法:二进制分解


为了提高效率,我们可以采用二进制优化的方法来处理物品的数量限制。
具体来说,对于第i种物品,我们将其数量mi拆分为若干组,每一组的数量分别为(1, 2, 4, …, res)
这样做的目的是让这些组合能够通过不同的组合方式表示从1到mi的所有数字。

例如,假设某物品的数量限制为13,那么我们可以将其拆分为:

  • 1 即(2^0)
  • 2 即(2^1)
  • 4 即(2^2)
  • 6 (13 - (1+2+4) = 6)

这样,我们就可以用这四个新的“物品”组合出任何从1到13的数量。比如:

  • 5 = 1 + 4
  • 7 = 1 + 2 + 4
  • 13 = 1 + 2 + 4 + 6

完成上述转换后,我们将问题转化为0-1背包问题,其中每组作为一个单独的“物品”。


实现步骤

  1. 对于每种物品,根据其数量mi进行二进制拆分,生成新的“物品”列表。
  2. 初始化dp数组,dp[0]通常初始化为0,因为当容量为0时无法放入任何东西。
  3. 遍历新生成的每个“物品”,然后从该物品的重量开始遍历到背包的容量C,更新dp数组。
    dp[j] = max(dp[j], dp[j-w[i]] + v[i]) 对于所有 j >= w[i]
    
    • 1
  4. 最终,dp[C]将包含能够放入容量为C的背包中的最大价值。

注意

  • 使用二进制优化可以显著减少计算量,特别是在物品的数量限制较大的情况下。
  • 在实际实现时,需要注意边界情况的处理,如物品数量mi为0的情况。

通过这种方法,我们可以有效地解决多重背包问题,并找到在给定背包容量下可获得的最大价值。



好了,实际运用的时候到了

实战演练


多重背包问题II https://www.acwing.com/problem/content/5/

题目描述

有 N N N 种物品和一个容量是 V V V 的背包。
第 i i i 种物品最多有 s i s_i si​ 件,每件体积是 v i v_i vi​,价值是 w i w_i wi​。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。

输入格式

第一行两个整数, N , V N,V N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N N N 行,每行三个整数 v i , w i , s i v_i, w_i, s_i vi​,wi​,si​,用空格隔开,分别表示第 i i i 种物品的体积、价值和数量。

输出格式

输出一个整数,表示最大价值。

数据范围

0 < N ≤ 1000 0 \lt N \le 1000 0<N≤1000
0 < V ≤ 2000 0 \lt V \le 2000 0<V≤2000
0 < v i , w i , s i ≤ 2000 0 \lt v_i, w_i, s_i \le 2000 0<vi​,wi​,si​≤2000

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2
  • 1
  • 2
  • 3
  • 4
  • 5

输出样例:

10
  • 1

本题数据范围增强了,考查多重背包的二进制优化方法。


code:

n, v = map(int, input().split())
v_w = []  # 存储物品的体积和价值的二进制分解
for i in range(1, n + 1):
    vi, wi, si = map(int, input().split())
    k = 1
    while si >= k:
        v_w.append((vi * k, wi * k))  # 二进制分解
        si -= k
        k *= 2
    # 处理剩余的部分
    if si > 0:
        v_w.append((vi * si, wi * si))

dp = [0] * (v + 1)  # 滚动数组优化
for i, (vi, wi) in enumerate(v_w):
    for j in range(v, vi - 1, -1):
        dp[j] = max(dp[j], dp[j - vi] + wi)
print(dp[v])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

时间复杂度优化为O(n*v*logs)


再进一步,利用单调队列维护窗口内最大值,避免重复计算
可以将时间复杂度优化为O(n*v),
在此就不赘述了,属于进阶技巧,后续会更新


END
如果有更多问题或需要进一步的帮助,可以在评论区留言讨论哦!
如果喜欢的话,请给博主点个关注 谢谢

注:本文转载自blog.csdn.net的查理零世的文章"https://blog.csdn.net/2401_87245677/article/details/145501387"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

108
Python
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top