完全背包
动态规划解题步骤 :
动态规划问题一般从三个步骤进行考虑。
步骤一:集合和集合的状态
所谓的集合,就是一些方案的集合。
用 g[i][j] 表示从前 i 种物品中进行选择,且总体积不大于 j 的各个选法获得的价值的集合。注意:g[i][j] 不是一个数,是一堆数。
例如 g[2][3] 从前 2 种物品中进行选择,且总体积不大于 3 的各个选法获得的价值的集合。
g[2][3] 的可选择方案包括:
方案一:都不选,总价值为 0。
方案二:选 1 件 物品 1,总价值为 2。
方案三:选 2 件物品 1,总价值为 4。
方案四:选 3件 物品 1,总价值为 6。
方案五:选 1 件物品 2,总价值为 4。
方案六:选 1 件物品 2,一件物品 1,总价值为 6。
所以 g[2][3] = {0,2,4,6,4,2}。
i j 取不同的值,对应不同的 g[i][j],也就是对应不同的集合。
用 f[i][j] 表示从前 i 种物品中进行选择,总体积小于等于 j 所能获得的最大价值。很明显,f[i][j] 就是 g[i][j] 中的最大值。i j 取不同的值,就对应不同的 f[i][j]。我们把 f[i][j] 叫做集合的状态。
例如 f[2][3] 表示从前 2 种物品中进行选择,且总体积不大于 3 的获得的最大价值。f[2][3] = max(g[2][3] ) = max( 0,2,4,6,4,2) = 6。
g[i][j] 的最大值就是 f[i][j]。
如果我们能把所有集合对应的最大值都求出来,即求出了 f[0][0] ~ f[N][V], f[N][V] 的含义是在前 N 种物品中进行选择,总体积不大于 V 所获得的最大价值,就是我们要找的答案。
注意,我们不需要把各个集合的所有元素都找出来,只需要求出各个集合的最大值,就能找到答案。下面就是如何求出各个集合的最大值。
步骤二:状态计算
g[i][j] 是从前 i 种物品中进行选择,且总体积不大于 j 的各个选法获得的价值的集合。
f[i][j] 是从前 i 种物品中进行选择,总体积小于等于 j 所能获得的最大价值。
f[i][j] 是集合 g[i][j] 的最大值。
所谓的状态计算是指,如何将把 f[i][j] 算出来。
如果把各个集合 g[i][j] 的状态 f[i][j] 求出来, f[N][V] 就是要找的答案。
回想一下 0 1 背包问题。
01 背包问题把 g[i][j]划分成了 A B 两部分,分别求出这两个部分对应的最大值,然后两者取最大值就是整体 g[i][j] 的最大值,就是 f[i][j]。
01 背包根据是否选择第 i 件物品,也就是第 i 件物品选 0 个还是 1 个,把 g[i][j] 划分成了 A B 两部分,分别求出这两个部分的最大值,然后两者取最大值就是整体 g[i][j] 的最大值,也就求出了 f[i][j]。
完全背包问题也是根据第 i 件物品的选择数量,把 g[i][j] 划分成不同的部分,分别求出各个部分的最大值,取各个部分最大值中的最大值,就是整体 g[i][j] 的最大值,也就求出了 f[i][j]。
因为每种物品的数量是无限的,根据第 i 种物品的选择数量可以把 g[i][j] 分为这样几部分:
A 部分: 第 i 种物品选 0 件。
B 部分:第 i 件物品选 1 件。
C 部分: 第 i 件物品选 2 件。
X 部分: 第 i 件物品选 x 件。
. . . . .
因为选择物品的总体积不能 j,所以第 i 件物品最多选多选j / vivi 向下取整件。
对于 A 部分:第 i 件物品选 0 件。等价于从前 i - 1 种物品中选择商品,且总体积不超过 j 的各个价值的集合,也就是 g[i - 1][j]。g[i - 1][j] 这个集合中的最大值是 f[i - 1][j] ,所以 A 部分的最大值就是 f[i - 1][j]。
对于 B 部分:第 i 件物品选 1 件, 1 个 i 物品会占据 vivi 的背包空间,剩下的背包空间为 j - vivi 。可以从前 i - 1 种物品中,选出总体积小于等于j - vivi 的物品放入背包。
从前 i - 1 种物品中,选出总体积小于等于j - vivi 的各个方案获得的价值集合为 g[i - 1][j - vivi ],所以 B 部分的元素为 g[i - 1][j - vivi ] 中各个元素加上 wiwi 。g[i - 1][j - vivi ] 中的最大值为 f[i - 1][j - vivi ],所以 B 部分的最大值为 f[i - 1][j - vivi ] + wiwi。
对于 X 部分:第 i 件物品选 x 件, x 个 i 物品会占据 x * vivi 的背包空间,剩下的背包空间为 j - x * vivi 。可以从前 i - 1 种物品中,选出总体积小于等于j - x * vivi 的物品放入背包。
从前 i - 1 种物品中,选出总体积小于等于j - x * vivi 的各个方案获得的价值集合为 g[i - 1][j - x * vivi ],所以 x 部分的元素为 g[i - 1][j - x * vivi ] 中各个元素加上 x * wiwi 。g[i - 1][j - x * vivi ] 中的最大值为 f[i - 1][j - x * vivi ],所以 B 部分的最大值为 f[i - 1][j - x * vivi ] + x * wiwi。
例如 g[2][4]。
第二种物品的体积为 2,选择物品的总体积不能超过 4。所以第二件物品可以选择:0件、1件、2件。
因此 g[2][4] 可以分成以下几部分:
A 部分:第二件物品选 0 件。A 部分的最大值为: f[i - 1][j - 0 * vivi] + 0 * wiwi 。 B 部分:第二件物品选 1 件。B部分的最大值为: f[i - 1][j - 1 * vivi ] + 1 * wiwi 。 C 部分:第二件物品选 2 件。C 部分的最大值为:f[i - 1][j - 2 * vivi ] + 2 * wiwi 。 g[2][4] 中的最大值为 max(A,B,C)。
通过上面分析,我们可以知道,g[i][j] 可以分成若干部分:
A 部分是第 i 种物品选 0 个对应所有选法获的价值的集合,最大值是 f[i - 1][j]。 B 部分是第 i 种物品选 1 个对应所有选法获的价值的集合,最大值是 f[i-1][j - vivi] + wiwi。 X 部分是第 i 种物品选 x 个对应所有选法获的价值的集合,最大值是 f[i - 1][j - x * wiwi]。 所以 g[i][j] 的最大值就是所有子集的最大值中最大的那个,也就是 f[i][j] = max(A, B ,····) 即:
展开式为:f[i] [j] = max( f[i-1][j] , f[i - 1][j - vivi]+w , f[i - 1][j - 2 * vivi] + 2 * w , f[i - 1][j - k * vivi ] + k * w , .....) 其中 k <= j / w。
从计算公式可以看出:
f[i][j] 是由 f[i - 1][j - k * vivi ] (0 <= k <= j / wiwi) 和 wiwi 计算出来的。 f[i][j]的值是可以从前面已经计算出的 f 值求出来。 如果我们能确定 f[i][j] 的一部分初始值,就能通过该公式,一步步计算得出 f[N][V],也就是我们要找的答案。 步骤三:确定初始值
完全背包问题的有些状态是能够直接确定的。
例如 f[0][0]。
f[0][0] 的含义是:
从前 0 种物品中选择,并且选出的物品总体积小于等于0 时所能得到的最大价值。 总体积小于等于 0,说明一种物品都不能选择。 因此 f[0][0] = 0。同理 f[1][0] = 0,f[2][0] = 0 ··· f[N][0] = 0。 有了这些初始值,通过 i 从 1 遍历 N,j 从 1 遍历 V,第 i 种物品的选择数量 k 从 0 遍历到 j / wiwi 就能一步步求出所有的 f[i][j] 了。
例如求 f[1][1]:
f[1][1] = max{f[0][1],f[0][0] + 2} = max(0,2) = 2。 求 f[1][2]:
f[1][2] = max{f[0][2],f[0][1] + 2,f[0][0] + 4} = max(0,2,4) = 4。 最后 f[N][V] 就是要找的答案。
这时候就可以写代码了:
#include<iostream>
using namespace std;const int N = 1010;int n, m;
int f[N][N], v[N], w[N];int main(){cin >> n >> m;for(int i = 1; i <= n; i ++ )cin >> v[i] >> w[i];for(int i = 0; i <= m; i++)//初始化{f[0][i] = 0;}for(int i = 1; i <= n; i ++ )for(int j = 0; j <= m; j ++ )for(int k = 0; k * v[i] <= j; k ++ )f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);//求出每一个 f[i][j]cout << f[n][m] << endl;
}
...
优化 :
动态规划的优化一般都是对代码或者状态计算方程进行一个等价变形。 在考虑动态规划问题的时候,一定要先把基本的形式写出来,然后再对它进行优化。
看一下 f[i][j] 和 f[i][j - vivi] 的求解公式:
f[i][j] = max( f[i-1][j] , f[i-1][j - vivi] + w , f[i-1][j - 2 * vivi] + 2 * w , f[i-1][j - 3 * vivi] + 3 * w , .....)。
f[i][j - vivi] = max( f[i-1][j - vivi] , f[i-1][j - 2 * vivi] + w , f[i-1][j - 3 * vivi] + 2 * w , .....) 。
由上两式,可得出如下递推关系:
f[i][j] = max(f[i][j-v] + w , f[i-1][j])
有了上面的关系,那么其实 k 循环可以不要了,核心代码优化成这样:
for(int i = 1; i <= n; i ++ ){for(int j = 0; j <= m; j ++ ){if(v[i] <= j)//第 i 种能放进去f[i][j] =max(f[i - 1][j], f[i][j - v[i]] + w[i]);else//如果第 i 件物品不能放进去f[i][j] = f[i - 1][j];}}
完整代码:
#include<iostream>
using namespace std;const int N = 1010;int n, m;
int f[N][N], v[N], w[N];int main()
{cin >> n >> m;for(int i = 1; i <= n; i ++ )cin >> v[i] >> w[i];for(int i = 1; i <= n; i ++ ){for(int j = 0; j <= m; j ++ ){if(v[i] <= j)f[i][j] =max(f[i - 1][j], f[i][j - v[i]] + w[i]);elsef[i][j] = f[i - 1][j];}}cout << f[n][m] << endl;
}
接着对比下完全背包的核心代码与 01背包的核心代码:
f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);//01背包f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]);//完全背包问题
//01背包代码优化这里有详细说明
因为和01背包代码很相像,我们很容易想到进一步优化。核心代码可以改成下面这样:
for(int i=1;i<=n;i++){for(int j=v[i];j<=m;j++)//注意了,这里的j是从小到大枚举,和01背包不一样{f[j] = max(f[j],f[j-v[i]]+w[i]);}
}
综上所述,完全背包的最终写法如下:
#include<iostream>
using namespace std;
const int N=1010;
int f[N];
int v[N],w[N];
int main(){int n,m;cin>>n>>m;for(int i = 1 ; i <= n ;i ++){cin>>v[i]>>w[i];}for(int i=1;i<=n;i++){for(int j=v[i];j<=m;j++){f[j]=max(f[j],f[j-v[i]]+w[i]);}}cout<<f[m]<<endl;
}相关文章:
完全背包
动态规划解题步骤 : 动态规划问题一般从三个步骤进行考虑。 步骤一:集合和集合的状态 所谓的集合,就是一些方案的集合。 用 g[i][j] 表示从前 i 种物品中进行选择,且总体积不大于 j 的各个选法获得的价值的集合。注意:g[i][j] 不是一个数…...
【软件测试】webdriver常用API演示(Java+IDEA+chrome浏览器)
1.元素定位方法 对象的定位应该是自动化测试的核心,要想操作一个对象,首先应该识别这个对象。一个对象就是一个人一样,他会有各种的特征(属性),如比我们可以通过一个人的身份证号,姓名…...
Linux安装MySQL 8.1.0
MySQL是一个流行的开源关系型数据库管理系统,本教程将向您展示如何在Linux系统上安装MySQL 8.1.0版本。请按照以下步骤进行操作: 1. 下载MySQL安装包 首先,从MySQL官方网站或镜像站点下载MySQL 8.1.0的压缩包mysql-8.1.0-linux-glibc2.28-x…...
多线程面试相关的一些问题
面试题 1. 常见的锁策略相关的面试题 2. CAS相关的面试题 3. Synchronized 原理相关的面试题 4. Callable 接口相关的面试题 1. 常见的锁策略 乐观锁 vs 悲观锁 悲观锁: 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都…...
【使用维纳滤波进行信号分离】基于维纳-霍普夫方程的信号分离或去噪维纳滤波器估计(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Vue+axios如何解决跨域
1、为什么会产生跨域? 出于浏览器的同源策略限制。 同源策略(Sameoriginpolicy)是一种约定,是浏览器的一种安全机…...
网络安全系统中的守护者:如何借助威胁情报 (TI) 提高安全性
在这篇哈巴尔网站上的推文中,我们将解释 TI 缩写背后的含义、为什么需要它、Positive Technologies 收集哪些网络威胁数据以及如何帮助企业预防网络威胁。我们将以四种情况为例,说明公司如何使用 PT Threat Intelligence Feeds 来发现恶意活动并预防攻击…...
并发编程 - CompletableFuture
文章目录 Pre概述FutureFuture的缺陷类继承关系功能概述API提交任务的相关API结果转换的相关APIthenApplyhandlethenRunthenAcceptthenAcceptBoththenCombinethenCompose 回调方法的相关API异常处理的相关API获取结果的相关API DEMO实战注意事项 Pre 每日一博 - Java 异步编程…...
IPIDEA参展ChinaJoy!探索未来创新科技的峰会之旅
中国最大的国际数码互动娱乐展会ChinaJoy即将于7月28日在上海举行,届时将聚集全球来自22个国家和地区的领先科技公司、创业者和技术专家,为参观者呈现一系列引人入胜的展览和活动。而IPIDEA作为参展商之一,将为参观者带来一场关于数字科技的奇…...
2023最新ChatGPT商业运营版网站源码+支持ChatGPT4.0+GPT联网+支持ai绘画(Midjourney)+支持Mind思维导图生成
本系统使用Nestjs和Vue3框架技术,持续集成AI能力到本系统! 支持GPT3模型、GPT4模型Midjourney专业绘画(全自定义调参)、Midjourney以图生图、Dall-E2绘画Mind思维导图生成应用工作台(Prompt)AI绘画广场自定…...
轮趣科技教育版ros小车键盘控制运动
我之前买的ros小车是单独买的底板,以为随便一个树莓派就可以,因为我以前有一个树莓派3B,后来买了单独的小车之后,发现只能使用树莓派4B,然后又单独买了一个树莓派4B,给装上镜像,安装ros-melodic…...
深入理解Python中的os.chdir()方法
深入理解Python中的os.chdir()方法 1. 简介 在Python中,os.chdir()方法用于改变当前的工作目录。工作目录是指当前正在执行的脚本所在的目录。通过使用os.chdir()方法,我们可以在脚本执行过程中切换到不同的目录。 在编写Python脚本时,我们…...
【Golang 接口自动化02】使用标准库net/http发送Post请求
目录 写在前面 发送Post请求 示例代码 源码分析 Post请求参数解析 响应数据解析 验证 发送Json/XMl Json请求示例代码 xml请求示例代码 总结 资料获取方法 写在前面 上一篇我们介绍了使用 net/http 发送get请求,因为考虑到篇幅问题,把Post单…...
LaTex语法(常用数学符号的语法和注意事项)
说明:[]括号表示把语法括起来,并不表示LaTex语法。 1. 求和符号(Σ) 这个符号的基本语法为:[\sum_{}^{}]。 符号有两种模式:内联数学模式(inside math mode)和显示数学模式(displayed math mode)。 内联数学模式:排版时使用各…...
Yunfly 一款高效、性能优异的node.js企业级web框架
介绍 Yunfly 一款高性能 Node.js WEB 框架, 使用 Typescript 构建我们的应用。 使用 Koa2 做为 HTTP 底层框架, 使用 routing-controllers 、 typedi 来高效构建我们的 Node 应用。 Yunfly 在 Koa 框架之上提升了一个抽象级别, 但仍然支持 Koa 中间件。在此基础之上, 提供了一…...
mac m1安装Centos9
先看结果(在mac M1 安装centos8 安装不成功的原因大部分是没有找到正确的系统) 由于Cnetos8 停服,现有mac m1 上能够按照的Centos8 并非由官方发布,因此寻找官方发布的能够在mac m1上安装的centos版本。 在YouTuBe上找到一个视频…...
深入理解mAP
0 介绍 mAP是目标检测任务最重要的评价指标。 mAP 是mean average precosion的缩写,mean 和 average都是平均的意思, 所以这个指标的计算涉及到2次平均。 mean是对所有类别的平均, 比如VOC 数据有20个类, 每个类别分别计算AP&…...
PostGis -基础、Springboot 整合、电子围栏处理
目的: 为什么要用PostgreSQL? 因为有时候我们需要存储 空间数据,如:存储一个 多边形 到数据。PostGis中 geometry、geography :基本空间数据类型,用于表达点线面等空间要素,具体类型涵盖了OGC的简单对象模…...
【Linux】多线程的补充
1 线程安全的单例模式 1.1 什么是单例模式 单例模式是一种 "经典的, 常用的, 常考的" 设计模式. 1.2 什么是设计模式 IT行业这么火, 涌入的人很多. 俗话说林子大了啥鸟都有. 大佬和菜鸡们两极分化的越来越严重. 为了让菜鸡们不太拖大佬的后腿, 于是大佬们针对一些…...
【MySQL】表的操作
今天我们来谈谈MySQL下对表的操作 目录 一、创建表 二、查看表 2.1 查看库中存有的表 2.2 查看表结构 2.3 查看表的创建语句 三、修改表 3.1 重命名表名 3.2 新增列 3.3 修改列的数据类型 3.4 删除列 3.5 重命名列 3.6 向表中插入数据 四、删除表 一、创建表 我…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
aardio 自动识别验证码输入
技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”,于是尝试整合图像识别与网页自动化技术,完成了这套模拟登录流程。核心思路是:截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...
