一文彻底搞懂01背包算法

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u014296502/article/details/80015722

0-1 背包问题:给定 n 种物品和一个容量为 C 的背包,物品 i 的重量是 wi,其价值为 vi

问:应该如何选择装入背包的物品,使得装入背包中的物品的总价值最大?

假设一个函数B是求解总价值的函数,有两个因变量n与C ;则我们的优化目标就变为

max.F(n,C,x).x0,1

展开公式其实就是:
F(n,C,x)=x1v1+x2v2+....+xnvn
std.x1w1+x2w2+...+xnwnC
xi0,1

x的取值范围为0或者1,代表着这个物品我们可以选择拿或者不拿,我们想要找出这样的01组合如:111001使得F(n,C,x)最大。
我们假设一个函数
B(n,C)=max.F(n,c,x)
也就是说B函数是一个能够自动组合x的取值使得F(n,c,x)达到最大。
再次理解这个B(n,c)这个函数的意义:从n个物品里面选物品,容量为C,能达到的最大价值。如何求解这个函数呢?我们可以细分目标,试想一下,如果想要在5个商品里面选择,得到最大总价值,那么肯定得先求得在4个物品里面选择,得到最大价值后,然后考虑第五个物品要不要放进去?放进去会不会超过容量限制,会不会得到一个最大价值。我们就得到了一个函数。
B(n,c)=B(n1,c);
B(n,c)=max{B(n1,c),B(n1,cwn)+vn};

这里存在一个困扰:如果有多余空间去放置的话,那么放置肯定比不放的价值大啊,因为我多放入一个物品了啊,也就是说选择不放的函数B(n1,x)肯定小与放置的函数B(n1,cw)+vn,说道这里你就犯了一个惯性错误,认为B(n1,x)B(n1,cw)所对应的F(n,c,x)中的x={x1,x2,.....xn}组合相同,在理解这个函数的意义:从n个物品里面选物品,容量为C,能达到的最大价值。这个两个函数组合不一定相同,为容量C约束条件变了。就会变为从n-1个物品里面选,容量为C与从n-1个物品里面选,容量为c-w且加上v,两者哪个大。彻底理解了函数B之后,我相信没有什么能够阻挡你学习这个算法了。
例:w={1,2},v={1,2},c=2
解:B(2,2)为最大价值,如果我们拿最后物品w=2,v=2,因为w=2=c,所以我们可以选择拿或者不拿
1、拿:如果确定拿走最后一个物品,则B(2,2)=B(2-1,2-2)+2=B(1,0)+2
2、不拿:如果确定不拿走最后一个物品,则B(2,2)=B(1,2);因为最后一个物品我选择不拿,所以情景肯定变为从1个物品里面选,容量为2,是否达到最大值,因此等式左右两边相等。
然后比较B(1,0)+2B(1,2)哪个大,很明显,对于B(1,0),已经没有容量去放置下一个物品,就相当于从0个物品里面选B(1,0)=B(0,0)=0B(1,0)+2=2则.求解B(1,2),代表着我只能去选择(第一件:2=1,v=1)的我要不要去拿,肯定得拿啊,再不拿就没东西可以拿了,结果为0,拿了话结果价值就为1
B(2,2)=max{B(1,0)+2,B(1,0)+2}=max{2,1}=2
这里写图片描述
显然这是个递归求解的过程,实现递归过程,并测试一下

capicaty=[0,1,2]
value=[0,1,2]

def  best_value(i,j):
    if i==0:
        return 0
    if j-capicaty[i]<0:
        return best_value(i-1,j)
    else:
        return max(best_value(i-1,j),best_value(i-1,j-capicaty[i])+value[i])

 print(best_value(2,2))


 result:2  

递归结果正确,但是如果数据量比较大的话,程序肯定会变的缓慢,递归会使得程序效率变差这个原因我就不解释了,但是如果我要求B(2,2)是不是要计算,B(1,2),B(0,2),如果要求B(1,2)是不是得求一下B(0,2),最后才能返回结果,我们是不是重复计算了B(1,2)与B(0,2)。如果要是能把每个计算的结果保存下来,下次就不必重复计算了,可以的,我们把递归转化为递推。
声明一个矩阵maxvalue[N][C],专门用来存放B函数的缓存结果,利用行列进行索引值,行代表有几个物品,列代表容量,这样的话如果要求B(2,2),就去索引第二个物品,容量为2 即maxvalue[2][2],找到这个值就ok了

maxvalue=[[0 for i in range(3)] for j in range(3)]
for k in range(1,3):
    for c in range(1,3):
        if c-capicaty[k]>=0:
            maxvalue[k][c]=max(maxvalue[k-1][c],maxvalue[k-1][c-capicaty[k]]+value[k])
        else:
            maxvalue[k][c]=maxvalue[k-1][c]

这里写图片描述
B(2,2)那么我们去索引,maxvalue[2][2]同样得到2的结果,这样的话这个算法你就掌握了,可以去到动态规划的世界玩耍一番,好好感悟一下,晦涩难懂的理论知识,状态,状态转移方程,把目标划分为子目标,分而治之,你会发现你看得懂了,完美。

展开阅读全文

没有更多推荐了,返回首页