数据结构与算法
背包问题03
题目类型描述: 给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择(每种物品数量不限),才能使得物品的总价格最高(from 百度百科)。
具象理解:
假设背包总容量top_weight为10,现共有四样物品(每样物品数目不限),他们的重量和价格分别为:
抽象建模:
这次我们采用较为简单的方式——构建两个一维数组(就像之前我们做到的那样,ws用来存储每个物品的重量,vs用于存储每个物品的价格)。然后选择最优方案。
初步分析:![背包问题03版](https://i-blog.csdnimg.cn/blog_migrate/f0f6fa9d6c8fd6a8c323ffd7af2c637a.png#pic_center)
当然,我想可能很多小伙伴见到这道题后最直观的想法就是:我可以挑选性价比高的物品,然后不断填充——贪心算法。这是我们在平时生活中积累处的经验影响了我们的思考方式。要知道人区别与机器的其中很重要一点就是经验的积累和学习,我们漫长的生活“帮助”我们有了这样的思考方式,习惯于用经验解决问题,但有时候这种想法会错,而且也不适用于机器(这是大多数编程工作者尽量避免的一点:按照我们人类的思考方式有时候得到的并不是最优解,而且通过编程语言让机器按照人类的方式思考这种做法至少是不利于算法优化的,结果的准确性也很难保障)。
在此我可以轻易举出反例来证明这种想法是错误的(top_weight=10):
如图,如果按照之前我们提到的贪心算法,2号物品很明显有更高的性价比,但是这样只装得下一个2号,总价格为8,可是我们如果装1号物品可以装俩,总价值为10(显然更好)!
显然,这种思考方式就有问题,那么我们该怎么思考呢?
深入分析:
仔细考虑我们又会发现,其实也并不是只要把背包装满就能得到最大利润,那么我们需要给计算机制定一个标准——一个帮助它选择的标准。对于每个物品,计算机有了两种选取方式——选 k 个(k>0),或者不选。它要做的事情很简单,从这两种情况中挑选最优解!这不就好起来了吗?在这种思路的实现途中我们需要用到递归的思路(以我们刚刚举出的反例为例):
package KnapsackProbleminDynamicProgramming;
public class Five {
static int[] ws={
0,5,7};
static int[] vs={
0,5,8};
public static void main(String args[]){
System.out.println(Solution(ws.length-1, 10));//10指top_weight
}
//i,j各自表示可选前i个物品,背包剩余容量为j。
public static int Solution(int i, int j){
int res=0;//用来存储结果
if(i==0||j==0) return 0;
else if(j<vs[i]