当前位置: 首页 > news >正文

完全背包

动态规划解题步骤 :

动态规划问题一般从三个步骤进行考虑。

步骤一:集合和集合的状态

所谓的集合,就是一些方案的集合。

用 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;
}

相关文章:

完全背包

动态规划解题步骤 : 动态规划问题一般从三个步骤进行考虑。 步骤一:集合和集合的状态 所谓的集合&#xff0c;就是一些方案的集合。 用 g[i][j] 表示从前 i 种物品中进行选择&#xff0c;且总体积不大于 j 的各个选法获得的价值的集合。注意&#xff1a;g[i][j] 不是一个数…...

【软件测试】webdriver常用API演示(Java+IDEA+chrome浏览器)

1.元素定位方法 对象的定位应该是自动化测试的核心&#xff0c;要想操作一个对象&#xff0c;首先应该识别这个对象。一个对象就是一个人一样&#xff0c;他会有各种的特征&#xff08;属性&#xff09;&#xff0c;如比我们可以通过一个人的身份证号&#xff0c;姓名&#xf…...

Linux安装MySQL 8.1.0

MySQL是一个流行的开源关系型数据库管理系统&#xff0c;本教程将向您展示如何在Linux系统上安装MySQL 8.1.0版本。请按照以下步骤进行操作&#xff1a; 1. 下载MySQL安装包 首先&#xff0c;从MySQL官方网站或镜像站点下载MySQL 8.1.0的压缩包mysql-8.1.0-linux-glibc2.28-x…...

多线程面试相关的一些问题

面试题 1. 常见的锁策略相关的面试题 2. CAS相关的面试题 3. Synchronized 原理相关的面试题 4. Callable 接口相关的面试题 1. 常见的锁策略 乐观锁 vs 悲观锁 悲观锁: 总是假设最坏的情况&#xff0c;每次去拿数据的时候都认为别人会修改&#xff0c;所以每次在拿数据的时候都…...

【使用维纳滤波进行信号分离】基于维纳-霍普夫方程的信号分离或去噪维纳滤波器估计(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

Vue+axios如何解决跨域

1、为什么会产生跨域&#xff1f; 出于浏览器的同源策略限制。 同源策略&#xff08;Sameoriginpolicy&#xff09;是一种约定&#xff0c;是浏览器的一种安全机…...

网络安全系统中的守护者:如何借助威胁情报 (TI) 提高安全性

在这篇哈巴尔网站上的推文中&#xff0c;我们将解释 TI 缩写背后的含义、为什么需要它、Positive Technologies 收集哪些网络威胁数据以及如何帮助企业预防网络威胁。我们将以四种情况为例&#xff0c;说明公司如何使用 PT Threat Intelligence Feeds 来发现恶意活动并预防攻击…...

并发编程 - CompletableFuture

文章目录 Pre概述FutureFuture的缺陷类继承关系功能概述API提交任务的相关API结果转换的相关APIthenApplyhandlethenRunthenAcceptthenAcceptBoththenCombinethenCompose 回调方法的相关API异常处理的相关API获取结果的相关API DEMO实战注意事项 Pre 每日一博 - Java 异步编程…...

IPIDEA参展ChinaJoy!探索未来创新科技的峰会之旅

中国最大的国际数码互动娱乐展会ChinaJoy即将于7月28日在上海举行&#xff0c;届时将聚集全球来自22个国家和地区的领先科技公司、创业者和技术专家&#xff0c;为参观者呈现一系列引人入胜的展览和活动。而IPIDEA作为参展商之一&#xff0c;将为参观者带来一场关于数字科技的奇…...

2023最新ChatGPT商业运营版网站源码+支持ChatGPT4.0+GPT联网+支持ai绘画(Midjourney)+支持Mind思维导图生成

本系统使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到本系统&#xff01; 支持GPT3模型、GPT4模型Midjourney专业绘画&#xff08;全自定义调参&#xff09;、Midjourney以图生图、Dall-E2绘画Mind思维导图生成应用工作台&#xff08;Prompt&#xff09;AI绘画广场自定…...

轮趣科技教育版ros小车键盘控制运动

我之前买的ros小车是单独买的底板&#xff0c;以为随便一个树莓派就可以&#xff0c;因为我以前有一个树莓派3B&#xff0c;后来买了单独的小车之后&#xff0c;发现只能使用树莓派4B&#xff0c;然后又单独买了一个树莓派4B&#xff0c;给装上镜像&#xff0c;安装ros-melodic…...

深入理解Python中的os.chdir()方法

深入理解Python中的os.chdir()方法 1. 简介 在Python中&#xff0c;os.chdir()方法用于改变当前的工作目录。工作目录是指当前正在执行的脚本所在的目录。通过使用os.chdir()方法&#xff0c;我们可以在脚本执行过程中切换到不同的目录。 在编写Python脚本时&#xff0c;我们…...

【Golang 接口自动化02】使用标准库net/http发送Post请求

目录 写在前面 发送Post请求 示例代码 源码分析 Post请求参数解析 响应数据解析 验证 发送Json/XMl Json请求示例代码 xml请求示例代码 总结 资料获取方法 写在前面 上一篇我们介绍了使用 net/http 发送get请求&#xff0c;因为考虑到篇幅问题&#xff0c;把Post单…...

LaTex语法(常用数学符号的语法和注意事项)

说明:[]括号表示把语法括起来&#xff0c;并不表示LaTex语法。 1. 求和符号(Σ) 这个符号的基本语法为&#xff1a;[\sum_{}^{}]。 符号有两种模式&#xff1a;内联数学模式(inside math mode)和显示数学模式(displayed math mode)。 内联数学模式&#xff1a;排版时使用各…...

Yunfly 一款高效、性能优异的node.js企业级web框架

介绍 Yunfly 一款高性能 Node.js WEB 框架, 使用 Typescript 构建我们的应用。 使用 Koa2 做为 HTTP 底层框架, 使用 routing-controllers 、 typedi 来高效构建我们的 Node 应用。 Yunfly 在 Koa 框架之上提升了一个抽象级别, 但仍然支持 Koa 中间件。在此基础之上, 提供了一…...

mac m1安装Centos9

先看结果&#xff08;在mac M1 安装centos8 安装不成功的原因大部分是没有找到正确的系统&#xff09; 由于Cnetos8 停服&#xff0c;现有mac m1 上能够按照的Centos8 并非由官方发布&#xff0c;因此寻找官方发布的能够在mac m1上安装的centos版本。 在YouTuBe上找到一个视频…...

深入理解mAP

0 介绍 mAP是目标检测任务最重要的评价指标。 mAP 是mean average precosion的缩写&#xff0c;mean 和 average都是平均的意思&#xff0c; 所以这个指标的计算涉及到2次平均。 mean是对所有类别的平均&#xff0c; 比如VOC 数据有20个类&#xff0c; 每个类别分别计算AP&…...

PostGis -基础、Springboot 整合、电子围栏处理

目的&#xff1a; 为什么要用PostgreSQL? 因为有时候我们需要存储 空间数据&#xff0c;如&#xff1a;存储一个 多边形 到数据。PostGis中 geometry、geography &#xff1a;基本空间数据类型&#xff0c;用于表达点线面等空间要素&#xff0c;具体类型涵盖了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 向表中插入数据 四、删除表 一、创建表 我…...

【七. Java字符串操作与StringBuilder高效拼接技巧】

7. java字符串 7.1 API 介绍&#xff1a;应用程序编程接口。在 Java 中&#xff0c;API 指的是 JDK 提供的各种功能类&#xff0c;这些类把底层实现封装好了&#xff0c;我们不用关心内部怎么写的&#xff0c;直接用就行 用 API 帮助文档步骤&#xff1a;以查Random类为例 打…...

现代网络安全攻防技术与发展现状

1. 引言 随着数字化转型进程的加速&#xff0c;全球信息化程度不断深入&#xff0c;网络安全问题日益凸显。根据最新的统计数据&#xff0c;2022年全球范围内的网络攻击事件较前一年增长了约41%&#xff0c;造成的经济损失高达超过6万亿美元。在这个背景下&#xff0c;了解现代…...

ESP8266远程控制:实现网络通信与设备控制

概述&#xff1a; 最近一直在弄esp8266的网络通信&#xff0c;但是一直都还没搞懂到底esp8266可不可以通过连接一个网络过后&#xff0c;在很远的地方使用网络将其关掉 在网上找了两个教程都有程序&#xff0c;都跑通了 第一个 第二个找不到了&#xff0c;但是程序有 CSDN上放文…...

Golang 配置国内代理

使用 GOPROXY 临时设置 export GOPROXYhttps://goproxy.cn,direct永久设置 go env -w GOPROXYhttps://goproxy.cn,direct再go get下载...

azure web app创建分步指南系列之二

为注册表授权托管标识 你创建的托管标识尚未获得从容器注册表中提取数据的授权。在此步骤中,你将启用授权。 返回容器注册表的管理页面: 在左侧导航菜单中,选择“访问控制 (IAM)”。选择“添加角色分配”。此屏幕截图显示了如何为容器注册表启用添加角色分配。在角色列表中…...

【linux】linux进程概念(四)(环境变量)超详细版

小编个人主页详情<—请点击 小编个人gitee代码仓库<—请点击 linux系列专栏<—请点击 倘若命中无此运&#xff0c;孤身亦可登昆仑&#xff0c;送给屏幕面前的读者朋友们和小编自己! 目录 前言一、基本概念二、认识常见的几个环境变量echo $ 查看某个环境变量env 显示…...

PyTorch中nn.Module详解

直接print(dir(nn.Module))&#xff0c;得到如下内容&#xff1a; 一、模型结构与参数 parameters() 用途&#xff1a;返回模块的所有可训练参数&#xff08;如权重、偏置&#xff09;。示例&#xff1a;for param in model.parameters():print(param.shape)named_parameters…...

79. 单词搜索-极致优化,可行性剪枝和顺序剪枝

给你一个目标字符串&#xff0c;和一个二维字符数组&#xff0c;判断在数组中是否能找到目标字符串。 例如&#xff0c;board [["A","B","C","E"],["S","F","C","S"],["A","…...

Electron-vite【实战】MD 编辑器 -- 系统菜单(含菜单封装,新建文件,打开文件,打开文件夹,保存文件,退出系统)

最终效果 整体架构 src/main/index.ts import { createMenu } from ./menu在 const mainWindow 后 // 加载菜单createMenu(mainWindow)src/main/menu.ts import { BrowserWindow, Menu, MenuItem, MenuItemConstructorOptions, dialog, shell } from electron import fs from…...

定制开发开源AI智能名片S2B2C商城小程序:数字营销时代的话语权重构

摘要&#xff1a;在数据驱动的数字营销时代&#xff0c;企业营销话语权正从传统媒体向掌握用户数据与技术的平台转移。本文基于“数据即权力”的核心逻辑&#xff0c;分析定制开发开源AI智能名片S2B2C商城小程序如何通过技术赋能、场景重构与生态协同&#xff0c;帮助企业重构营…...