python解决0-1背包问题(超直观)

关于背包问题的话,其实百度百科已经讲得很详尽了:

https://baike.baidu.com/item/%E8%83%8C%E5%8C%85%E9%97%AE%E9%A2%98/2416931?fr=aladdin

但是太详尽了,而且太自顶向下,符号一多更容易搞蒙头。那么我就从自底向上,来得出动态规划的状态转移方程吧。

来看一个0-1背包的例子:

weight=[2,2,6,5,4]
value=[3,6,5,4,6]
weight_most=10
有5个物体,考虑装入背包,背包的总承重是10。第一个物体重2,价值是3,如此类推。那么怎样才能在不超过背包承重的范围下,使得背包装的物体的总价值最高呢?哈哈,先考虑一些简单的情况如果只允许装前1件物体,不,这样还不够简单。

自底向上分析:

1、最简单是只允许装前0件物体,即什么都不装,那这样的话,管你背包承重0也好,10也好,100也好。那么总价值最高都是0。

2、好了,难一点点,只允许装前1件物体,也就是只允许装第1件了。那么不要马上跳到承重10,先从承重0开始,如果背包只允许承重0的话,那么总价值最高也是0。|承重1呢,第一件物体重2,装不下,怎么办呢,那就不装呗还能怎么办,瞄一眼前0件(也就是不装)承重1的情况,总价值是0,所以总价值还是0咯。|好了,承重是2呢?2-2=0装得下,装的话比前0件(不装)承重2的总价值要高!那你装不装?肯定要装,那么总价值最高就是3。|那么承重是3呢?3-2=1,还有1的重量可以装,卧槽,可是装不了,因为,只允许装前一件,如果换个说法的话,就是在承重1的情况下允许装前0件(哈哈,就是不给装嘛)。那么不用看之后承重是5也好,10也好,总价值最高就是3。

3、只允许装前1件还是很简单的,那么好戏来了!!!允许装前两件呢?承重0,总价值最高0,不用看。|承重1呢,装不下,看前1件(不装)承重1是0,那么前2件承重1是0。|承重2呢,关键了!允许装前2件,两件都装得下,那比较一下吧,是允许装前1件承重2总价值比较高呢?还是?对,还是什么?还是我新允许的第2件价值比较高呢,怎么比较规范表达呢?因为这件是装得下,2-2=0,那么装完之后呢?是不是回归到允许前1件承重0的情况了?很好,那么加上这种情况的总价值最高为0,0+6>3,所以前2件承重2总价值最高就是6了。前2件承重3也差不多。|承重4呢?是前1件承重4总价值为3比较高呢?还是装了第二件之后,回归到前1件承重2,加起来,3+6=9比较高呢?那么就是9!|前5件,承重10咧?

4、回到我们的总问题,emmmmm,你应该心里有b数了。不就3种情况嘛,承重0或者允许装前0件,全是总价值最高0;如果新允许的第i件装的那件装不下,那就看允许的前i-1件对应的承重的总价值最高咯;如果装得下,那么就要比较允许装前i-1件对应的承重的总价值最高这承重减去新装的那件,回归到那种情况的总价值最高相加。没了,就三种情况,状态转移方程就这样出来了。


实现代码如下:

import numpy as np

weight=[2,2,6,5,4]
value=[3,6,5,4,6]
weight_most=10
def bag_0_1(weight,value,weight_most):#return max value
    num = len(weight)
    weight.insert(0,0)#前0件要用
    value.insert(0,0)#前0件要用
    bag=np.zeros((num+1,weight_most+1),dtype=np.int32)#下标从零开始
    for i in range(1,num+1):
        for j in range(1,weight_most+1):
            if weight[i]<=j:
                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)
    return bag[-1,-1]

result=bag_0_1(weight,value,weight_most)
print(result)
输出:
15
如果你想看bag这个矩阵也可以:
[[ 0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  3  3  3  3  3  3  3  3  3]
 [ 0  0  6  6  9  9  9  9  9  9  9]
 [ 0  0  6  6  9  9  9  9 11 11 14]
 [ 0  0  6  6  9  9  9 10 11 13 14]
 [ 0  0  6  6  9  9 12 12 15 15 15]]
以上。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值