DP背包问题

news2024/12/25 2:28:28

目录

一、前言

二、0/1背包

1、装箱问题(lanqiaoOJ题号763)

2、2022(2022年国赛填空题,lanqiaoOJ题号2186)

三、完全背包

1、小明的背包2(lanqiaoOJ题号1175)

四、分组背包

五、多重背包


一、前言

本文主要讲了0/1背包、完全背包、分组背包、多重背包的相关概念。

二、0/1背包

1、装箱问题(lanqiaoOJ题号763)

【题目描述】

有一个箱子容量为 V (正整数,0≤V≤20000),同时有 n 个物品 (0<n≤30),每个物品有一个体积(正整数)。要求 n 个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

【输入描述】

输入第一行,一个整数,表示箱子容量。第二行,一个整数 n,表示有 n 个物品。接下来 n 行,分别表示这 n 个物品的各自体积。

【输出描述】

输出一行,表示箱子剩余空间。

0/1背包的简化版,不管物品的价格。把体积 (不是价格) 看成最优化目标:最大化体积。

dp=[0]*20010
V=int(input())
n=int(input())
c=[0]*40
for i in range(1,n+1):
    c[i]=int(input())
for i in range(1,n+1):
    for j in range(V,c[i]-1,-1):
        dp[j]=max(dp[j],dp[j-c[i]]+c[i])
print(V-dp[V])

2、2022(2022年国赛填空题,lanqiaoOJ题号2186)

【题目描述】

将 2022 拆分成 10 个互不相同的正整数之和,总共有多少种拆分方法?注意交换顺序视为同一种方法。注意交换顺序视为同一种方法。

例如:

2022 = 1000 + 1022

2022 = 1022 + 1000

视为同一种方法。

【思路】

  • 题目求 10 个数的组合情况,这十个数相加等于 2022。因为是填空题可以不管运行时间,看起来可以用暴力 for 循环 10 次,加上剪枝。
  • 然而暴力的时间极长,因为答案是:379187662194355221。
  • 这一题其实是 0/1 背包:背包容量为 2022,物品体积为 1~2022,往背包中装 10 个物品,要求总体积为 2022,问一共有多少种方案。
  • 与标准背包的区别:是求方案总数。

定义dp[][[]:dp[i][j][k]表示数字 1~i 取 j 个,和为 k 的方案数。

下面的分析沿用标准 0/1 背包的分析方法。

从 i-1 扩展到 i,分两种情况:

1)k ≥ i。数 i 可以要,也可以不要。

      要 i。从 1~i-1 中取 j-1 个数,再取 i,等价于 dp[i-1][j-1][k-i]。

      不要 i。从 1~i-1 中取 j 个数,等价于 dp[i-1][j][k]

      合起来:dp[i][j][k] = dp[i-1][j][k] + dp[i-1][j-1][k-i]

2)k < i。由于数 i 比总和 k 还大,显然 i 不能用。有:dp[i][j][k] = dp[i-1][j][k]

【不用滚动数组】

1)k≥i。dp[i][j][k] = dp[i-1][j][k] + dp[i-1][j-1][k-i]

2)k<i。dp[i][j][k] = dp[i-1][j][k]

dp=[[[0]*2222 for i in range(11)] for j in range(2222)]
for i in range(0,2023):
    dp[i][0][0]=1       #特别注意这个初始化
for i in range(1,2023):
    for j in range(1,11):
        for k in range(1,2023):
            if k<i:
                dp[i][j][k]=dp[i-1][j][k]
            else:
                dp[i][j][k]=dp[i-1][j][k]+dp[i-1][j-1][k-i]
print(dp[2022][10][2022])

【用滚动数组】

1)k>=i。dp[i][j][k]=dp[i-1][j][k]+dp[i-1][j-1][k-i]

2)k<i。dp[i][j][k]=dp[i-1][j][k]

dp=[[0]*2222 for i in range(11)]
#for i in range(0,2023):
dp[0][0]=1               #特别注意这个初始化
for i in range(1,2023):
    for j in range(10,0,-1):    #10个数
        for k in range(i,2023): #k>=i
            dp[j][k]+=dp[j-1][k-i]
print(dp[10][2022])

三、完全背包

1、小明的背包2(lanqiaoOJ题号1175)

【题目描述】

小明有一个容量为 C 的背包。这天他去商场购物,商场一共有 N 种物品,第 i 种物品的体积为 ci,价值为 wi,每种物品都有无限多个。小明想知道在购买的物品总体积不超过 C 的情况下所能获得的最大价值为多少,请你帮他算算。

【输入描述】

输入第 1 行包含两个正整数 N,C,表示商场物品的数量和小明的背包容量。第 2~N+1 行包含 2 个正整数 c,w,表示物品的体积和价值。1<=N<=10^3,1<=C<=10^3,1<=ci, wi<=10^3。

【输出描述】

输出一行整数表示小明所能获得的最大价值。

  • 思路和 0/1 背包类似。0/1 背包的每种物品只有 1 件,完全背包的每种物品有无穷多件,第 i 种可以装 0 件、1 件、2 件、C/ci 件。
  • 定义 dp[i][j]:把前 i 种物品 (从第 1 种到第 i 种) 装入容量为 j 的背包中获得的最大价值。
  • 把每个 dp[i][j] 都看成一个背包:背包容量为 j,装 1~i 这些物品。最后得到的 dp[N][C] 就是问题的答案:把 N 种物品装进容量 C 的背包的最大价值。
  • 在 0/1 背包问题中,每个物品只有拿与不拿两种;而完全背包问题,需要考虑拿几个。

完全背包的代码和 0/1 背包的代码相似,只多了一个 k 循环,用来遍历每种物品拿几个。

def solve(n,C):
    for i in range(1,n+1):
        for j in range(0,C+1):
            if i==1:
                dp[i][j]=0
            else:
                dp[i][j]=dp[i-1][j]
            for k in range(0,j//c[i]+1):    #k*c[i]<=j  #在容量为j的背包中放几个
                dp[i][j]=max(dp[i][j],dp[i-1][j-k*c[i]]+k*w[i])
    return dp[n][C]

N=3011
dp=[[0]*N for j in range(N)]
w=[0]*N
c=[0]*N
n,C=map(int,input().split())
for i in range(1,n+1):
    c[i],w[i]=map(int,input().split())
print(solve(n,C))

复杂度:O(nC)

四、分组背包

分组背包问题:

  • 有一些物品,把物品分为 n 组,其中第 i 组第 k 个物品体积是 c[i][k],价值是 w[i][k];
  • 每组内的物品冲突,每组内最多只能选出一个物品;
  • 给定一个容量为 C 的背包,问如何选物品,使得装进背包的物品的总价值最大。

【解题思路】

解题思路与 0/1 背包相似。

  • 0/1 背包 dp[i][j]:把前 i 个物品 (从第1个到第i个) 装入容量为 j 的背包中获得的最大价值。
  • 分组背包 dp[i][j]:把前 i 组物品装进容量 j 的背包 (每组最多选一个物品),可获得的最大价值。
  • 状态转移方程:dp[i][j] = max{dp[i-1][j],dp[i-1][j-c[i][k]] + w[i][k]}

dp[i-1][j]表示第 i 组不选物品,dp[i-1][j-c[i][k]] 表示第 i 组选第 k 个物品。

求解方程需要做 i、j、k 的三重循环。

【滚动数组】

状态转移方程:dp[i][j]=max{dp[i-1][j], dp[i-1][j-c[i][k]]+w[i][k]}

用滚动数组,变为:dp[j]=max{dp[j], dp[j-c[i][k]]+w[i][k]}

dp=[0]*N
for i in range(1,n+1):      #遍历每个组
    for j in range(C,-1,-1):  #枚举容量
        for k in range(1,C+1):  #用k枚举第i组的所有物品
            if j>=c[i][k]:      #第k个物品能装进容量j的背包
                dp[j]=max(dp[j],dp[j-c[i][k]]+w[i][k])  #第i组第k个
print(dp[C])

五、多重背包

多重背包问题:

  • 给定 n 种物品和一个背包,第 i 种物品的体积是 ci,价值为 wi,并且有 mi 个,背包的总容量为 C。
  • 如何选择装入背包的物品,使得装入背包中的物品的总价值最大?
  • 对比完全背包:一个容量为 C 的背包,有 N 种物品,第 i 种物品的体积为 ci,价值为 wi,每种物品都有无限多个。
  • 两者非常相似。

【解题思路1:转化为0/1背包】

【解题思路2:直接DP】

状态转移方程:dp[i][j]=max{ dp[i-1][j], dp[i-1][j-k*c[i]]+k*w[i] }

用滚动数组,变为:dp[j]=max{ dp[j], dp[j-k*c[i]]+k*w[i] }

dp=[0]*N
for i in range(1,n+1):      #枚举物品
    for j in range(C,c[i]-1,-1):  #枚举背包容量
        for k in range(1,m[i]+1):  #用k遍历第i组的所有物品
            if j>=c[i]*k:           #第k个物品能装进容量j的背包
                dp[j]=max(dp[j],dp[j-k*c[i]]+k*w[i])
print(dp[C])

【解题思路3:二进制拆分优化】

一种简单而有效的技巧。

  • 例如第 i 种物品有 mi=25 个,这 25 个物品放进背包的组合,有 0~25 的 26 种情况。
  • 不过要组合成 26 种情况,其实并不需要 25 个物品。
  • 根据二进制的计算原理,一个十进制整数 X,可以用 1、2、4、8、... 这些 2 的倍数相加得到,例如 25 = 16 + 8 + 1,这些 2 的倍数只有 logX 个。
  • 题目中第 i 种物品有 mi 个,用 logmi 个数就能组合出 0~mi 种情况。总复杂度从O(C* \sum_{i=1}^{n}mi)优化到O(C* \sum_{i=1}^{n}\log mi)。

 【二进制差分优化】

  • 注意拆分的具体实现,不能全部拆成 2 的倍数,而是先按 2 的倍数从小到大拆,最后是一个小于等于最大倍数的余数。
  • 保证拆出的数相加在 [1, mi] 范围内,不会大于mi。
  • 例如 mi =25,把它拆成1、2、4、8、10,最后是余数 10,10<16=24,这 5 个数能组合成 1~25 内的所有数字,不会超过 25。
  • 如果把 25 拆成 1、2、4、8、16,相加的范围就是 [1, 31] 了。

【例题】

【输入描述】

第一行是整数 n 和 C,分别表示物品种数和背包的最大容量。接下来 n 行,每行三个整数 wi、ci、mi,分别表示第 i 个物品的价值、体积、数量。

【输出描述】

输出一个整数,表示背包不超载的情况下装入物品的最大价值。

N=100010
w=[0]*N
c=[0]*N
m=[0]*N
xw=[0]*N
xc=[0]*N
xm=[0]*N    #新的

n,C=map(int,input().split())
for i in range(1,n+1):
    w[i],c[i],m[i]=map(int,input().split())   #到此输入完毕

#以下是二进制拆分
xn=0        #二进制拆分后的新物品总数量
for i in range(1,n+1):
    j=1
    while j<=m[i]:      #例:m[i]=2
        m[i]-=j         #减去已经拆分的
        xn+=1
        xc[xn]=j*c[i]   #新物品的体积
        xw[xn]=j*w[i]
        j<<=1           #二进制枚举:1,2,4...
    if m[i]>0:          #最后一个是余数
        xn+=1
        xc[xn]=m[i]*c[i]
        xw[xn]=m[i]*w[i]

#以下是滚动数组版本的0/1背包
dp=[0]*N
for i in range(1,xn+1):     #枚举物品
    for j in range(C,xc[i]-1,-1):       #枚举背包容量
        dp[j]=max(dp[j],dp[j-xc[i]]+xw[i])
print(dp[C])

以上,DP背包问题

祝好

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/187301.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kylin 4.0.1 分布式集群安装部署

目录1. 安装依赖2. 安装Kylin(kylin1上操作)2.1 下载解压2.2 修改conf/kylin.properties2.3 下载Mysql驱动包和创建Mysql数据库2.4 hive-site.xml复制到spark的conf目录2.5 配置环境变量(两台kylin服务器)2.6 kylin运行环境检查2.7 ConfigurationException问题(没有则忽略)2.8 …

神经网络--从0开始搭建全连接网络和CNN网络

前言&#xff1a; Hello大家好&#xff0c;我是Dream。 今天来学习一下如何从0开始搭建全连接网络和CNN网络&#xff0c;并通过实验简单对比一下两种神经网络的不同之处&#xff0c;本文目录较长&#xff0c;可以根据需要自动选取要看的内容~ 本文目录&#xff1a;一、搭建4层全…

Spark核心RDD详解(设计与运行原理,分区,创建,转换,行动与持久化)

RDD设计背景与概念 在实际应用中&#xff0c;存在许多迭代式算法&#xff08;比如机器学习、图算法等&#xff09;和交互式数据挖掘工具&#xff0c;这些应用场景的共同之处是&#xff0c;不同计算阶段之间会重用中间结果&#xff0c;即一个阶段的输出结果会作为下一个阶段的输…

go: GOPATH entry is relative; must be absolute path: “F:oocode“.

系列文章目录 文章目录系列文章目录前言一、可以先查看一下啊二、gopath和goroot变量要和设置的一致总结前言 在安装hertz 之类的 总会弹出go 的不合法 等 出现这样的错误 要不就是go的不合法 会爆红 说go无这种命令 go&#xff1a;术语“ go”未被识别为cmdlet&#xff0c;函…

Hystrix断路器

目录 一、概述 &#xff08;一&#xff09;分布式系统面临的问题 &#xff08;二&#xff09;Hystrix是什么 &#xff08;三&#xff09;能干吗 &#xff08;四&#xff09;官网 &#xff08;五&#xff09;Hystrix官宣&#xff0c;停更进维 二、Hystrix重要概念 &…

JAVA开发(springBoot之HikariDataSource)

HikariDataSource是springBoot自带的数据源管理工具。应该是有zaxxer公司提供贡献给spring社区的。它是一款优秀的数据库连接池工具&#xff08;新的东西一般会吹吹牛&#xff09;&#xff0c;号称 Java WEB 当前速度最快的数据源&#xff0c;相比于传统的 C3P0 、DBCP、Tomcat…

【数据结构】认识顺序表

目录 1、先来认识一下线性表 1.1、对非空的线性表或者线性结构的特点&#xff1a; 1.2、线性表的实现方式 2、顺序表 2.1、定义一个类&#xff0c;实现顺序表 2.2、顺序表的操作方法 2.2.1、打印顺序表&#xff08;display&#xff09; 2.2.2、获取顺序表的长度&#x…

Rancher 中使用 Longhorn 备份恢复数据卷

全文目录导航0. 前言1. NFS 安装配置1.1 安装 nfs 及 rpcbind1.2 创建共享目录1.3 配置访问权限1.4 限制 showmount -e 防止漏洞扫描1.5 防火墙配置2. Longhorn 备份配置2.1 在 Longhorn UI 中配置3. 数据卷备份恢复操作3.1 创建示例工作负载3.2 创建测试数据3.3 创建数据卷备份…

车载以太网 - SomeIP测试专栏 - SomeIP Header - 03

前面已经简单的介绍了整帧SomeIP报文的组成部分,由于Ethernet报文头都是通用的,因此不会做详细的介绍,当然后面在介绍TC8中的TCP、UDP、IPv4、IPv6的时候也会做简单的介绍。不过在这里就不做介绍了,我们直接介绍SomeIP。 SomeIP Header 一、Message ID Message ID是由Serv…

Web3中文|构建Web3融资交易:股权和内部代币分配的比例

2017年&#xff0c;首次币发行&#xff08;ICO&#xff0c;Initial Coin Offering&#xff0c;也称首次代币发售、区块链众筹&#xff0c;是用区块链把使用权和加密货币合二为一&#xff0c;来为开发、维护、交换相关产品或者服务的项目进行融资的方式&#xff09;的融资方式激…

聚观早报 | 抖音超市上线;首架国产大飞机 C919 完成首次飞行

今日要闻&#xff1a;抖音超市上线&#xff1b;首架国产大飞机 C919 完成首次飞行&#xff1b;小鹏汽车计划有 5 款车型上市&#xff1b;2023年春节档电影总票房67.58亿元&#xff1b;亚洲首富被空头重创抖音超市上线 1 月 28 日消息&#xff0c;抖音超市已上线抖音 App&#x…

Javadoc(文档注释)详解

Java 支持 3 种注释&#xff0c;分别是单行注释、多行注释和文档注释。文档注释以/**开头&#xff0c;并以*/结束&#xff0c;可以通过 Javadoc 生成 API 帮助文档&#xff0c;Java 帮助文档主要用来说明类、成员变量和方法的功能。文档注释只放在类、接口、成员变量、方法之前…

vue+element高度仿照QQ音乐,完美实现PC端QQ音乐

一.前言 QQ音乐官网&#xff1a;点击访问作者成品效果预览&#xff1a;点击访问作者其他博客成品汇总预览&#xff1a;点击访问 暂时源码并没有提供其他获取渠道&#xff0c;私聊作者获取即可&#xff0c;或通过博客后面名片添加作者&#xff0c;很简单&#xff01; 二.主要…

创建的vue项目--打包

自创建的项目&#xff08;未使用项目框架&#xff09;&#xff0c;使用weabpack打包 1.在package.json文件中配置 2.在控制台执行打包命令npm run build 打包完成后&#xff0c;会在项目中生成一个dist文件夹&#xff0c;其中就是打包生成的静态文件 3.打开index.html&…

RocketMq基础详解

1、RocketMq的架构&#xff1a; 在RocketMq中有四个部分组成&#xff0c;分别是Producer&#xff0c;Consumer&#xff0c;Broker&#xff0c;以及NameServer&#xff0c;类比于生活中的邮局&#xff0c;分别是发信者&#xff0c;收信者&#xff0c;负责暂存&#xff0c;传输的…

找到二叉树中的最大搜索二叉树

题目 给定一棵二叉树的头节点 head&#xff0c;一致其中所有节点的值都不一样&#xff0c;找到含有节点最多的搜索二叉树&#xff0c;并返回这棵子树的头节点。 示例 分析 树形dp套路&#xff1a;如果题目求解目标是S规则&#xff0c;则求解流程可以定成以每一个节点为头节点…

【前端】如何判断是页面滚动还是窗口滚动

在写项目的时候遇到这个问题&#xff0c;现在举两个例子来记录这个问题。 页面滚动 html: <div class"temp"><template v-for"item in 100"><div>{{ item }}</div></template> </div>css: .temp {height: 100px;o…

老马闲评数字化「3」业务说了算还是技术说了算?

原文作者&#xff1a;行云创新CEO 马洪喜 导语 前两集和大伙聊了一下“数字化不转型行不行”以及“你的企业急不急着转”这两个话题。后面收到不少朋友的消息&#xff0c;说写的挺好&#xff0c;但“急着转、不敢转”的情况非常的普遍&#xff0c;有没有啥好主意给说一说。 麦…

冬去春来,ToB行业压缩的弹簧就要迸发了

目前来看&#xff0c;认知、实践、技术、服务这四方面的新变化&#xff0c;都将成为2023年企业数智化业务需求“井喷”的重要原因。 作者|周羽 出品|产业家 2023&#xff0c;冬去春来。 不止于字面。新的一年&#xff0c;中国的ToB厂商即将迎来“拨云见日”的朗朗晴空。 …

[文件上传工具类] MultipartFile 统一校验

目录​​​​​​​ 1. 创建上传文件的统一校验类 包含功能: -> 1. 多文件上传校验 -> 2. 文件名字校验(特殊符号) -> 3. 文件后缀校验 2. 使用方式 建议: 在文件上传开始的位置添加 -> 两个重载方法, 单文件 多文件都支持 -> 示例: 直接可以用, 任意位…