您的位置:首页 > 其它

经典算法之—背包问题

2016-12-18 18:39 573 查看

一.完全背包问题

问题描述:有一个背包容量为M,一堆物品其重量表示为W={w(1),w(2),…},物品相应的价值V={v(1),v(2),…},现在要求将物品中的一部分或全部,放入背包。要求:装入物品的总价值最高;同时满足装入物品总重量不超过M;对单个物品而言,状态可为:装入背包、不装入背包、一部分装入背包。
假设装入的物品为从w(i)到w(j),则有:



对于完全背包而言,我们采用的常见算法为:贪心算法。贪心规则为:每次放入的物品必须满足单位重量价值最高,即v(i)/w(i)最大
example:



第一步:计算单位重量价值:



第二步:放物品,按照单位重量价值来说6>5>4,因此放入顺序为w(1)、w(2)、w(3)。
显然w(1)完全放入后,背包未满;因此完全放入w(2)后,背包仍未满;但是此时若继续全部放入w(3),显然无法全部放入,只能放入三分之二的w(3)。

二.0/1背包问题

相对于完全背包问题而言,0/1背包问题多了一条规则:
物品放入规则,要么全部放入,要么不放入;不能部分放入!!
这个看似把问题简单化的规则,实际上让问题变得更加复杂。仔细想想就知道先前的贪心算法在这里失效了。因为前面的贪心规则无法保证单位重量价值最大物品一定被取到。
对于0/1背包问题,常采用的算法是:动态规划。之前的一篇关于动态规划详细讲解的文章:http://blog.csdn.net/zk_j1994/article/details/53700782
显然对于动态规划而言,最核心的事情就是寻找“状态转移函数”!!!
在寻找状态转移函数之前,说说下面这个装包过程最注意的一点就是,我们是尝试性装包,也就是说,一边往里面放,但受容量限制,还有可能拿走背包里面之前的物品,以满足不超重!!!寻找状态转移函数
(1)假设我们正在将物品向背包里面瞎装一通,此时恰好装到第i个物品。
(2)假设我们运气足够好,前面装了的i-1个恰好是局部最优解。换句话说,不可能找到其他i-1个物品放进背包能拥有更大的效益值。
(3)由于是0/1背包问题,此时我们必须要决定第i个物品到底放不放入背包?在这里,放入不放入最直观的解释就是:如果放入物品,整个效益值提高,就决定放入;反之,则不放入这里要注意了,因为我们是既往里面装,又可能往外面拿的过程。受容量限制,可能你把第i个放进去了,同时也需要从里面拿一个出来。!自然分两种情况讨论;
(4)当第i个物品不放入背包时,设设总的效益值为C[i-1,j],其中i-1表示背包中已经放入了i-1个物品,j表示背包的容量。(这里的i,j主要是为了编程的方便,因为是通过循环的方式逐渐增大i,j来选择物品是否放入的,可参考图1。)
(5)当第i个物品放入背包,放入背包之后,总的效益值就应该为C[i-1,j-w(i)]+v(i),其中i表示背包中已经放入了i个物品,j-w(i)表示背包剩余的容量。
(6)比较C[i-1,j]和C[i-1,j-w(i)]+v(i)的大小,来决定是否放入。如果C[i-1,j]<C[i,j-w(i)]+v(i),放入;否则不放入。
因此状态转移方程为:



example:



计算情况如图1:
 


图1
代码实现:

############################
#动态规划之0/1背包问题
#by:zkj
#2016年12月18日
############################
from numpy import zeros

def pack(weight,value,capacity):
itemCnt = len(weight) #物品数量
totalValue = zeros([itemCnt+1,capacity+1],int) #存放历史最优解的数组
for i in range(0,itemCnt+1): ##状态转移函数实现
for j in range(0,capacity+1):
if (i == 0) or (j == 0):
totalValue[i][j] = 0
elif j < weight[i-1]:
totalValue[i][j] = totalValue[i-1][j]
else:
totalValue[i][j] = max(totalValue[i-1][j],totalValue[i-1][j-weight[i-1]] + value[i-1])
return totalValue

def printResult(totalValue,weight,value,capacity):
itemCnt = len(weight)
print("背包能装的最大效益值:\n",max(totalValue[itemCnt]))
print("装入背包的物品有:")
i = itemCnt;j = capacity
while i >= 0:
if totalValue[i][j] == totalValue[i-1][j-weight[i-1]] + value[i-1]:
print(i,end = "") #结尾不换行
j = j-weight[i-1]
i -=1
return

weight = (5,3,7,4) #物品重量
value = (3,2,9,5) #物品价值
maxCapacity = 15 #背包容量
stateMat = pack(weight,value,maxCapacity)
printResult(stateMat,weight,value,maxCapacity)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法