贪心算法之装箱问题

问题描述

装箱问题可简述如下:设有编号为 0、1、…、n - 1 的 n 种物品,体积分别为
v0、v1、…、vn-1。将这 n 种物品装到容量都为 V 的若干箱子里。 约定这 n 种物品的体积均不超过 V ,即对于 0≤ i<n,有 0<vi ≤ v。不同的装箱方案所需要的箱子数
目可能不同。装箱问题要求使装尽这 n 种物品的箱子数要少。

贪心求解

使用一种贪心策略:每次都想将当前体积最大的物品装入箱中,在这块类似于这个问题 ->>> 贪心算法之多机调度问题
其实在生活中这也是很常见的一种做法,在没有充足时间去考虑如何最优解决这类问题时直觉(第六感 狗头保命)告诉我们可以这么去试试。
更直接的一个例子,力扣上有这么一道题:
在柠檬水摊上,每一杯柠檬水的售价为 5 美元。

顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 注意,一开始你手头没有任何零钱。

注:上面黑体部分内容引自力扣LeetCode860 柠檬水找零
很明显,当客户给我们$20进行找零时,自然而然地就给ta找了一张$10加上一张$5,为什么这么做?面对$20,我们有两种方案可以使用:

  • 找三张$5给顾客
  • 找一张$10 以及一张 $5 给顾客

选择第二种方案的原因对于做生意的老板应该不陌生,营业过程中我们需要备上一部分零钱在交易时方便找零,不至于出现无法找零的尴尬局面,这是商人们所想的,在上题中也同样适用。
但贪心算法的弊端也很明显:不考虑之前解带来的影响,仅仅为了达到当前最优解,这样”一根筋“的策略也不能在任何情况下得到最优解。
如只有面值分别为 1、5 和 11 单位的硬币,而希望找
回总额为 15 单位的硬币。按贪婪算法,应找 1 个 11 单位面值的硬币和 4 个 1 单
位面值的硬币,共找回 5 个硬币。但最优的解应是 3 个 5 单位面值的硬币。

这里使用贪心算法可以得到我们较为满意的解:具体做法如下↓

使用几个变量进行记录:

static int boxSize;//每个箱子的大小
static int n;//共 n 个物品
static int useBoxNums = 1;//使用箱子的数量
int* cases = reinterpret_cast<int*>(malloc(100 * sizeof(int)));//申请100个int大小的数组

假设现有6个物品体积分别为 5 2 3 4 5 6 需要用体积为 6 的箱子装入,箱子数量不限,使用尽可能少的箱子完成任务。
使用一维数组 cases 记录各物品的体积:
在这里插入图片描述

另再创建一个二维数组 loadCondition 记录每个箱子装入物品的情况,最后创建一个一维数组记录着每个箱子装入物品的数量(初始时均为0),作此记录的原因是:在后面的遍历输出结果的时候我们不清楚每个箱子的物品装入数量,而在生成数组时使用了malloc函数仅仅获得了一块连续空间,我们未对其进行初始化,若遍历越界会出现异常导致程序崩溃。
在对数组进行排序时我产生了使用sort函数(包含在 algorithm 头文件下)外加 lambda表达式以简化排序所需要的代码量:

sort(cases[0], cases[n - 1],
		[](int& a, int& b) ->bool {
   
			return a > b;
		}
	);//对n个物品的体积降序排序

无奈sort内部并未重载传参为普通数组的情况,出现以下异常: 在这里插入图片描述

无奈之下只能手写快排,这也难不倒我,反手就是一个递归版的快速排序,接下来就是很简单的遍历环节了:对排序后的每个物品遍历,依次装入箱中。

具体实现可以参照代码注释,算法思路较为简单,这里不再一一列出,敬请谅解。

实现代码

#
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nepu_bin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值