月球美容计划之维尼的背包(基础篇)

2024-08-22 14:18

本文主要是介绍月球美容计划之维尼的背包(基础篇),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

背包放在了寒假集训安排比较靠前的位置,虽然时间长,但遗忘的还不是很厉害,但是重新复习起来,却发现背包难度要在最短路,最小生成树等初等图论之上。背包的适用范围太广泛了,正是这种应用广泛还可以举一反三的算法,越是难以掌握。

一直在看背包九讲,看它把背包问题模型化并给出了出色的模板代码。但是看完更感觉背包不像一种算法,更像一种思想,我们就是把各种问题模拟成背包问题,那么,模型化并尝试举一反三,不失为学习背包的良策。

但实在是无法深入各个模型,背包一拖再拖,逢一批出洞烧烤之际,离群把总结敲完,尝试把心得总结,确定C语言模板,以备后用。

01背包

01背包才是最基础的背包模型,各种其他背包都可以化为01背包模型。

01背包的题目情景也很单纯:

有 件物品和一个容量为 的背包。放入第 件物品耗费的费用是 C[i],得到的

价值是 W[i]。求解将哪些物品装入背包可使价值总和最大。

其中模型的关键特点如下:

1.有限种物品,

2.每种物品只有一个,

3.每个物品有且只有两种状态,装入背包 || 不装入,

4.背包体积一定;

基本思路

01背包的基本思路来自其关键特点:每种物品有且只有两种状态,装入(1),或不装入(0),然而,考虑第i件物品放入体积为V的背包的时候是在考虑前i - 1件物品放入体积为V的背包基础之上产生的,而在考虑第i件物品的时候,我们能且只能做把第i件物品放入背包或者不放入背包,所以,假如我们已经有了前i - 1个物品的最优解,那么我们做第i个物品的决断是很简单的,就是比较一下放和不放的收益。

所以我们便得到了01背包的状态转移方程:

F[i][v]  =  max (F[i − 1][v] , F[i − 1][v − C[i]] + W[i]);

然后我们的假定条件(已知前i - 1个物品的最优解)是可得的,所以,对于这样的算法,就有了可以实现的代码:

int qmax (int a,int b){return a > b ? a : b;}....memset (dp,0,sizeof (dp));for (i = 1;i < n;i++)for (k = C[i];k <= V;k--){if (k >= C[i])dp[i][k] = qmax(dp[i - 1][k],dp[i - 1][k - C[i]] + W[i]);}


 

当然,这用了二维空间,背包九讲也介绍了如果优化空间复杂度,(Ps’因为题目要求不同,不代表二维比一维次,有时需要背包中间值,二维比一维更好些)变二维为一维,代码如下:

for (i = 0;i < n;i++)for (k = V;k <= C[i];k--){if (k >= C[i])dp[k] = qmax(dp[k],dp[k - C[i]] + W[i]);}


 

 

他的优化原理是因为第i行之与第i - 1行有关,因此,前面的没有存储的必要,当前一行的数据被使用过,就直接覆盖掉好了,不一定要必须保存下来,但是也正是如此,优化的时候一定要注意第二层循环一定要有V执行到C[i],原因是k - C[i]<=k,也就是说,你在生成第i行数据的时候,利用的第i - 1行的数据不能被覆盖掉,然而,第i行的生成要利用同行位置靠前的数据,因此,从后向前覆盖正好可以避免这个问题。

完全背包

完全背包也是非常重要的背包模型,也是寒假学的两个背包模型之一,其实就是01背包的简单升级版,其问题情境是这个样子的:

有 种物品和一个容量为 的背包,每种物品都有无限件可用。放入第 种物品

的费用是 C[i],价值是 W[i]。求解:将哪些物品装入背包,可使这些物品的耗费的费用总

和不超过背包容量,且价值总和最大。

不讨论它的关键特点,之找出他和01异同:

相同点:

1.都是有限个物品

2.都是一定以及的背包

3.都追求利益最大化

不同点:

1.01背包每种物品有限,有且只有一个,而完全背包没有限制

2.01背包只需要为每种物品考虑选取两个状态(放或不放)之一,而完全背包不仅需要考虑每种物品的放或不放,还有考虑放多少。

 

基本思路

背包九讲种介绍了不止一种的思路(包括性价比排序,转化为01背包),其中最基础的方法虽然我不想总结但的确很直白的说出什么是完全背包,其状态转移方程:

F[i][v] = max{F[i − 1][v − kC[i]] + kW[i]| 0 ≤ kCi≤ v}

但其过高的时间复杂度让我提不起兴趣,因此,我只想总结生成出模型代码更高效更简单的那种,也就是那个O(VN)的算法:

先说他的状态转换方程:

F[i][v] = max(F[i − 1][v],F[i][v − C[i]] + W[i])

其基本思路是这个样子的,先抛开每种物品放几个不说,先把问题分解为每种物品放与不放和每个物品放几个两个问题,那么,只需要考虑第i件物品能不能放这一个问题就好了,

那么,就可以写成这样的代码模型(一维):

for (i = 0;i < n;i++)for (k = C[i];k <= V;k++){if (k >= C[i])dp[k] = qmax(dp[k],dp[k - C[i]] + W[i]);}(二维)for (i = 1;i < n;i++)for (k = C[i];k <= V;k++){if (k >= C[i])dp[i][k] = qmax(dp[i - 1][k],dp[i][k - C[i]] + W[i]);}


 

其实比较01和完全的代码模型,发现差别不大,在一维模型中,差别反而就是当时强调不能犯的错误for (k = C[i];k <= V;k++)。其实这样的原因很简单,因为状态转移方程比较的是F[i − 1][v],F[i][v − C[i]] + W[i]之间的大小关系,当准备装入第i件物品的时候,不仅仅需要判断第i - 1 件,也需要判断第i件,原因很简单,完全背包放入某种物品的数目没有限制,当你每次装完一个这个物品的时候,不代表这个物品不能再被装入,也就是这样,导致在构建一维数组的时候,可以直接使用第i行的数据,来进行判断,是不是可以再多装一个同类物品。

多重背包

有一种背包叫做多重背包,然而在寒假集训中胖学长没有讲,迫于当时时间有限,背包九讲也就没有及时跟上,九讲看完两讲就去做题了,但是当看完第3讲第4讲才发现背包的灵活,也更坚定的认为学好模型很简单,用好模型定不容易,固认为越是灵活的东西,越是不容易掌握。

先说一下多重背包的问题情境:

有 种物品和一个容量为 的背包。第 种物品最多有 M[i]件可用,每件耗费的

空间是 C[i],价值是 W[i]。求解将哪些物品装入背包可使这些物品的耗费的空间总和不超

过背包容量,且价值总和最大。

根据题目情境,很容易就能找出多重背包的特色,多重背包很像完全背包但又有差异,其关键特点就是:每种物品不再是无限个而是有限个。

也正是因为多重背包与完全背包相似而差异不大,所以多重背包的解决算法就是从完全背包上发展而来。

那么就可以说一下基本算法:

其状态转移方程:F[i][v] = max{F[i − 1][v − ∗ C[i]] + k ∗ W[i]| 0 ≤ ≤ M[i]},复杂度是 O(V ΣMi)

我一点也不看好以上的思路,但是背包九讲提出把多重化为01的思路还是通用性挺好的,但是我还没有做过多重背包的题目,现在也不过就是空谈理论。

所以就截取背包九讲的两个方法:

方法一:

将第 种物品分成若干件 01 背包中的物品,其中每件物品有一个系

数。这件物品的费用和价值均是原来的费用和价值乘以这个系数。令这些系数分别为

1,2,22...2k1,Mi− 2k+ 1,且 是满足 Mi− 2k+ 1 > 0 的最大整数。例如,如果 Mi

为 13,则相应的 k = 3,这种最多取 13 件的物品应被分成系数分别为 1,2,4,6 的四件

物品。

这个就是把多重背包看做01背包,用到了“拆分物品”的思想,因为还没敲过这个方法,还带找时间做过多重背包的题目亲身实践。

方法二:

设 F[i,j] 表示“用了前 种物品填满容量为 的背包后,最多还剩

下几个第 种物品可用”,如果 F[i,j] = 则说明这种状态不可行,若可行应满足

≤ F[i,j] ≤ Mi。最终 F[N][0...V ] 便是多重背包可行性问题的答案。

 

没有实践就没有收获,多重背包只能说有了个大体的认识,也许某次遇见它会有个做题的方向,但还是最好找时间找找多重的题目做做。

 

尾声

本想一篇文章就把背包写完,没想到越写越多,在图书馆敲了两个小时,才发现写的只是个基础,而后续应用以及拓展根本没涉及,只能分篇了。又需要找时间写写背包的拓展应用。

 

Ps`:背包题目还是做得少,所能想到的根本拓展不开。

这篇关于月球美容计划之维尼的背包(基础篇)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1096504

相关文章

从基础到高级详解Python数值格式化输出的完全指南

《从基础到高级详解Python数值格式化输出的完全指南》在数据分析、金融计算和科学报告领域,数值格式化是提升可读性和专业性的关键技术,本文将深入解析Python中数值格式化输出的相关方法,感兴趣的小伙... 目录引言:数值格式化的核心价值一、基础格式化方法1.1 三种核心格式化方式对比1.2 基础格式化示例

redis-sentinel基础概念及部署流程

《redis-sentinel基础概念及部署流程》RedisSentinel是Redis的高可用解决方案,通过监控主从节点、自动故障转移、通知机制及配置提供,实现集群故障恢复与服务持续可用,核心组件包... 目录一. 引言二. 核心功能三. 核心组件四. 故障转移流程五. 服务部署六. sentinel部署

从基础到进阶详解Python条件判断的实用指南

《从基础到进阶详解Python条件判断的实用指南》本文将通过15个实战案例,带你大家掌握条件判断的核心技巧,并从基础语法到高级应用一网打尽,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录​引言:条件判断为何如此重要一、基础语法:三行代码构建决策系统二、多条件分支:elif的魔法三、

Python WebSockets 库从基础到实战使用举例

《PythonWebSockets库从基础到实战使用举例》WebSocket是一种全双工、持久化的网络通信协议,适用于需要低延迟的应用,如实时聊天、股票行情推送、在线协作、多人游戏等,本文给大家介... 目录1. 引言2. 为什么使用 WebSocket?3. 安装 WebSockets 库4. 使用 We

从基础到高阶详解Python多态实战应用指南

《从基础到高阶详解Python多态实战应用指南》这篇文章主要从基础到高阶为大家详细介绍Python中多态的相关应用与技巧,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、多态的本质:python的“鸭子类型”哲学二、多态的三大实战场景场景1:数据处理管道——统一处理不同数据格式

MySQL数据类型与表操作全指南( 从基础到高级实践)

《MySQL数据类型与表操作全指南(从基础到高级实践)》本文详解MySQL数据类型分类(数值、日期/时间、字符串)及表操作(创建、修改、维护),涵盖优化技巧如数据类型选择、备份、分区,强调规范设计与... 目录mysql数据类型详解数值类型日期时间类型字符串类型表操作全解析创建表修改表结构添加列修改列删除列

Python 函数详解:从基础语法到高级使用技巧

《Python函数详解:从基础语法到高级使用技巧》本文基于实例代码,全面讲解Python函数的定义、参数传递、变量作用域及类型标注等知识点,帮助初学者快速掌握函数的使用技巧,感兴趣的朋友跟随小编一起... 目录一、函数的基本概念与作用二、函数的定义与调用1. 无参函数2. 带参函数3. 带返回值的函数4.

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

从基础到进阶详解Pandas时间数据处理指南

《从基础到进阶详解Pandas时间数据处理指南》Pandas构建了完整的时间数据处理生态,核心由四个基础类构成,Timestamp,DatetimeIndex,Period和Timedelta,下面我... 目录1. 时间数据类型与基础操作1.1 核心时间对象体系1.2 时间数据生成技巧2. 时间索引与数据

安装centos8设置基础软件仓库时出错的解决方案

《安装centos8设置基础软件仓库时出错的解决方案》:本文主要介绍安装centos8设置基础软件仓库时出错的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录安装Centos8设置基础软件仓库时出错版本 8版本 8.2.200android4版本 javas