关于背包问题的话,其实百度百科已经讲得很详尽了:
但是太详尽了,而且太自顶向下,符号一多更容易搞蒙头。那么我就从自底向上,来得出动态规划的状态转移方程吧。
来看一个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]]
以上。