用动态规划解决0-1背包问题
问题概述
给定以有限容量(capacity/space)的背包,和一些由体积(space)和价值的(value)的物品,求一个方案,用这个背包能够装下更多的物品
解决思路
- 先解决前i个物品在容量为任意j(最大值为背包容量)的背包下,能够装下的价值量
- 再解决在1的基础上继续解决前i+1个物品在任意j的背包下,能装下的最大价值量。所以,DP(i+1,j)=max{DP(i,j),DP(i,j-s(i+1))+v(i+1)}。
- 第一种情况即第i+1个物品未被装进来,此时问题等价于“前i个物品,在容量为j时最大装载量”,第二种情况即第i+1个物品被装进来了,此时问题等价于“前i个物品在容量为j-s(i+1)时的最大装载量”,显然可得,当j<s(i+1)时,第二种情况不可能成立,所以只取第一种情况。
- 在3的基础上,我们可以提出两个边界条件:DP(0,j)=0 即无物品可装时,无论背包容量有多大,装载量皆为0。DP(i,0)=0,即背包没有容量时,无论有什么物品,都不可能装下。
实现思路
为此,我们可以实现一个二维矩阵DP[i,j],来存储我们上面提到的DP(i,j).
其在初始化时,需要将第一行和第一列都初始化为0.然后逐行逐列根据上一节第2条所提到的情况进行更新。
到此为止,我们获得了在任意容量和任意物品供选择的情况下,所能装下的最大价值。我们还需要得到具体的装载方案。
为此,我们可以用以下方案来得到具体的装载方案。
- 访问DP(n,v),与DP(n-1,v)做对比,若相等则说明存在物品n被放入背包的最佳方案。
- 同时与DP(n-1,v-s(n))+v(n)做对比,若相等则说明存在物品n-1 未被放入背包的最佳方案。
- 对1和2中,符合条件(相等)的元素,做重复操作,直至第一个物品被确认是否存在被放入背包的最佳方案。
- 需要注意的是,如果被访问的元素,出现DP[i,j]其中j <s(i),那实现DP[i,j]的方案中必然不可能存在物品i。
- 得到这个方案的过程类似于一个树状图。
囿于时间仓促,本人用深度优先的方式,实现仅给出其中一种最佳方案的方式。
代码实现
为了使矩阵操作更加高效和便捷,这里使用了numpy.ndarray
dp_01.py:
import numpy as np
class dp_01:
def __init__(self,items,capacity):
self.items=items
self.num=len(self.items)
self.capacity=capacity
self.matrix=np.zeros((self.num+1,self.capacity+1))
self.matrix=np.asarray(self.matrix)
def update_the_matrix(self):
#需注意的是,物品的计数从第1个开始,而不是第0个
#为了同记载物品情况的元组/列表相适配,items[i-1]指的就是第i个物品。
for i in range(1,self.num+1,1):
for j in range(1,self.capacity+1,1):
#当背包容量小于物品i体积时时,显然不可能存在物品i被装入的方案
if j <self.items[i-1][1]:
self.matrix[i][j]=self.matrix[i-1][j]
else:
if self.matrix[i-1][j]>=self.matrix[i-1][j-self.items[i-1][1]]+self.items[i-1][0]:
self.matrix[i][j]=self.matrix[i-1][j]
else:
self.matrix[i][j] = self.matrix[i-1][j-self.items[i-1][1]]+self.items[i-1][0]
print(self.matrix)
#仅给出一种方案,有空余时间的读者可以按照本人的思路尝试使用广度优先的方式得到所有最佳解
def get_the_best_idea(self):
idea=[]
node=self.matrix[self.num,self.capacity]
j=self.capacity
for i in range(self.num,0,-1):
if node==self.matrix[i-1][j]:
node=self.matrix[i-1][j]
break
else:
idea.insert(0,i)
j-=self.items[i-1][1]
node=self.matrix[i-1][j]
idea=np.array(idea)
idea=idea
return idea
测试
测试数据集(同程振波老师的MOOC)
物品 | 价值 | 体积 |
---|---|---|
1 | 4 | 3 |
2 | 5 | 4 |
3 | 6 | 5 |
测试截图
测试结论
可见我们成功的实现了用二维动态规划解决01背包问题
测试结论
可见我们成功的实现了用二维动态规划解决01背包问题