JavaScript:完全背包问题

92 阅读6分钟

题目描述

这里借用一个题目的描述来说明要解决问题的背景。

LiYuxiang是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是LiYuxiang,你能完成这个任务吗?

此题和原题的不同点:

1.每种草药可以无限制地疯狂采摘。

2.药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!

一、 什么是背包算法

背包算法的基础标准描述为:当前有N件商品,每件商品都有不同的价值v和重量w。我们要把这些商品放在容量为L的背包中,实现背包中的价值最大化。(第i件商品的价值为v[i],重量为w[i])。上面的题目中的条件之一:草药无限(每件商品可以重复放入背包)即表明了该问题是完全背包问题。

二、 背包算法的应用

背包算法在我看来是一种“性价比”算法。即我们在有限的条件下得到最大的收获。例如曾经有个节目可以让嘉宾在有限的时间内选购满满购物车的货品。这个场景及其符合背包算法。或者例如我们在考试的时侯,都会尽可能的选择简单并且分数又多的题先做。同时我们也可以应用到其他问题上去。比如在选择购买多种原材料时,尽可能的缩小原材料成本。投资时对多种投资产品的选择组合。

三、 背包算法的原理

背包问题需要用到动态规划算法。当我们装一个商品的时侯需要判断几个条件:

  1. 该商品的重量和背包大小的关系。如果背包的总容量小于商品的重量,那就GG,根本不用考虑了。
  2. 商品的重量小于背包剩余容量。即背包中之前装入的商品不需要拿出来就可以把当前商品装下,那也不用考虑,直接装就好了。
  3. 商品的重量小于背包总容量,但是剩余空间不够装了。那我们就需要考虑衡量一下,拿出来原有的一部分商品,装入现在的商品是不是划算的。

从上面的三个条件可以看出最重要的就是第三条,我们需要判断价值。假设我们背包可以装8kg东西,现在有三个商品(商品都是以袋为单位销售不可拆分):

苹果香蕉草莓
3kg2kg5kg
¥45¥20¥150

我们以1kg为单位打表: 第一次打表

0kg1kg2kg3kg4kg5kg6kg7kg8kg
000000000
苹果000¥45¥45¥45¥90¥90¥90
香蕉000000000
草莓000000000

第二次打表

0kg1kg2kg3kg4kg5kg6kg7kg8kg
000000000
苹果000¥45¥45¥45¥90¥90¥90
香蕉00¥20¥45¥45¥65¥90¥90¥110
草莓000000000

最终打表结果:

0kg1kg2kg3kg4kg5kg6kg7kg8kg
000000000
苹果000¥45¥45¥45¥90¥90¥90
香蕉00¥20¥45¥45¥65¥90¥90¥110
草莓00¥20¥45¥45¥150¥150¥170¥195

如表我们的最终排列结果。

核心判断为:bag[i-1][j]bag[i-1][j-k*w[i]] + k*v[i] 的价值哪个大。 我来说明上面的变量都代表了什么:

  • bag[i][j] 代表了我们在看到第i个商品时,背包容量占用了jkg时,背包内物品的价值。

  • 那么bag[i-1][j] 就代表了我们在看到第i-1个商品时,背包容量占用了jkg时,背包内装的价值。

  • v[i]代表了当前商品的价值,k*v[i]代表了kv[i]的价值(商品不限量)。

  • w[i]代表了当前商品的重量,k*w[i]代表了kw[i]的重量。

  • bag[i-1][j-k*w[i]]就代表了上一个情况下,背包装了k个i商品时,余下空间在上一状态的最大价值。

所以,我们的核心判断种需要 上一个情况下的背包的所有状态。当我们把背包中 k*w[i]的空间腾出来用来装k个i商品,加上剩余空间可以装的商品的最大价值。如果它小于上一个状态下bag[i-1][j]所装货品的价值,那么我们就没必要替换这部分空间了。


//两个循环
for (3) //3个商品
	for (8) // 8种占用空间的情况(1kg-8kg)

// 核心判断
if (bag[i-1][j] > bag[i-1][j-k*w[i]] + k*v[i]) {
	bag[i][j] = bag[i-1][j];
} else {
	bag[i][j] = bag[i-1][j-k*w[i]] + k*v[i];
}

其实回到生活上,我们的想法跟这个是一样的,当我们有个背包要装满的时侯,我们先看到了苹果,那么当然的,我们要尽可能多的把苹果装到包包里。如果有剩余空间装不下那也只能浪费着。然后我们发现了香蕉,我们会开始想着怎么用香蕉代替一部分苹果把空间填满。在这个思考的过程中,我们会一直比较什么样的组合价值最大。草莓也是一样。

其实如开头所说,我说这是“性价比”。上面我们商品出现的顺序是随机的。其实我们装东西判断价值,其实就是装性价比最高的物品。 不过同时需要考虑到空间的利用率。如果我们事先把性价比高的物品排在前面,那么效率会提高不少。

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情