0-1背包问题

问题描述:

  有一个最大承重量为w的背包,第i件物品的价值为a1[i],第i件物品的重量为a2[i],将物品装入背包,求解背包内最大的价值总和可以为多少?举个例子:a1 = [100, 70, 50, 10], a2 = [10, 4, 6, 12], w = 12, 该问题的最终结果是:背包内的最大价值总和为 120,分别装入重量为4和6的物品,能获得最大价值为 120.

算法分析:

  刚开始,拿到这个问题的时候,可能出现最多的就是这张图.首先要明白这张表是自底向上,从左到右生成的。最重要的是该方法的思维,数值和我题目可能不太一样,首先先分析这张图:蓝色的框代表背包的承受重量,分别是从0到10,对应于我题目上的12;紫色的框代表所存在的物体编号:a~e;黄色的框依次对应各个物体的重量;同理绿色的框依次对应各个物体的价值.蓝色框的作用其实就是假设背包最大承受重量的范围,事实上这里是10,不过为了分析过程,我们选择从0开始分析,即什么都不装.

  从第一个蓝框看起,也就是第'1'列,注意前提(自底向上),包最大承受重量为1,而物体的重量最低是2,显然无法装下的,第一列价值全是0.再看第'2'列,还是自底向上,很显然cde物体的重量为6,5,4,而背包最多能装2,cde明显为0,再看b重量恰好是2,重点的来了:如果选择装下,那么2-2=0,背包剩余0空间,但是获得价值3.如果选择不装,继续往上看,恰巧重量也是2,但是却可以获得价值6,我们的目的是价值最大化,明显装6划算,这里就有个权衡的过程:装还是不装.从算法层面上来说,2种情况都要考虑,选择其中最大的价值即可.说到这里应该是有一点味道了吧.继续向下分析第'3'个框一个道理,看第'4'个蓝色框,从e开始正好重量为4,背包容量也是4,装的话价值就是6,因为空间没了.不装的话,价值就为0了,既然选择不装就继续向上分析,cd物体重量分别为5,6,明显超过背包空间4,显然无法装.继续往上看b,容量为2,此时你又有2个选择:b装还是不装.不装的话,继续看a物体,此时你可以选则装与不装,不装总价值0,装的话总价值6;b装的话,背包空间剩下4-2=2,获得价值3;继续往上走,a物体恰巧重量又是2,你也会选择装与不装.不装的话你的价值就是3,装的3+6=9,依次类推.

  上方的分析已经够详细了,代码实现的思路也就出来了.其实就是个比较和决策的过程.代码如下所示:

import numpy as np 
weight=[10,4,6,12]
value=[100,70,50,10]
weight_max=12
#加0操作只是为了给什么都不装的情况下赋值为0,不然下面代码会报错.
num=len(weight)+1
weight.insert(0,0)
value.insert(0,0)
bag=np.zeros((num,weight_max+1),dtype=np.int32)
#这里从1开始的原因,是因为前面已经有了添0操作并赋值.
for i in range(1,num):
    for j in range(1,weight_max+1):
        #如果物体重量小于背包存在的空间,简而言之:背包存在空间的情况下,会有2种情况:
        # 1.将第i个物体放进背包里,那么价值就为前i-1物体的最大价值量与当前第i个物体的价值量总和.
        # 2.第i个物体不放进背包里,那么价值就为前i-1物体的最大价值量
        # 该问题不管怎么走,都为面临着放与不放的问题,也就是0-1背包问题.     
        if weight[i]<=j:   
            #这里可以想象下, j-weight[i]为剩余空间的容量,比如剩余空间为1,即从第1列去查表(第1列对应着不同的重量,也对应不同的价值)                  
            bag[i][j]=max(bag[i-1][j-weight[i]]+value[i],bag[i-1][j])
        else:
            bag[i][j]=bag[i-1][j]    
print(bag[-1][-1])   

  其实这种解法符合思维,但是可能理解起来很费力,不过有个比较好理解的方式,参考知识星球上某京东算法工程师的代码,个人觉得看起来还是很通俗易懂的,使用了递归的方法.

a1 = [100, 70, 50, 10]
a2 = [10, 4, 6, 12]
W = 12

def f(i, w):
    # 基本情况:背包可装载重为 0 时,表明它不能再装物品了,自然价值为 0;i < 0 表明没有物品可装入了,自然价值也为 0
    if w == 0 or i < 0:
        return 0
    elif a2[i] > w:
        return f(i-1, w)
  
    return max(a1[i] + f(i-1, w-a2[i]),
               f(i-1, w))

r = f(3, W)
print(r) # 120

  需要说明的是:以上代码决策方式是由后向前,重要参数也在代码里说明.写这篇文章的目的完全是作为自己的一份笔记,最后,因为该方法是在知识星球里学的,所以好东西应该分享,附上星球链接.

                                                                     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值