问题:有n件物品,每件物品的重量是Wi(i=1,2,…n),物品的价值是Pi(i=1,2,…n),背包能承受的最大重量的T,问如何放置物品,可以使背包中的物品的价值最大?
想法:
最原始的想法:先找到物品的所有组合,共有2n -1个,然后遍历所有的组合,判断物品的质量是否<=T,这种算法的时间复杂度是O(2n+1),空间复杂度是O(2n).不管是时间复杂度还是空间复杂度都比较高,这种算法的可行度比较低,应该要找其他的解决办法
动态规划:我们可以把这个问题拆分成更小的问题,如果小问题解决了,大问题随之也就解决了。假设F[i-1][w]表示对于前i-1件物品来说背包中的物品的最大收益,那么对于第i件物品来说,就有2中可能,如果放第i件物品,则F[i][w] = max(F[i-1][w-w[i]] + p[i], F[i-1][w]);如果不放第i件物品,则F[i][w] = F[i-1][w] .我们需要计算出w为0,1,2,3…T时,背包的物品的收益
|n = 5 #物品的数量
w = [5,4,7,2,6] #每件物品的重量
p = [12,3,10,3,6] #每件物品的价值
物品\重量 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 12 | 12 | 12 | 12 | 12 | 12 | 12 | 12 |
2 | 0 | 0 | 0 | 0 | 3 | 12 | 12 | 12 | 12 | 15 | 15 | 15 |
3 | 0 | 0 | 0 | 0 | 3 | 12 | 12 | 12 | 12 | 15 | 15 | 15 |
4 | 0 | 0 | 3 | 3 | 3 | 12 | 12 | 15 | 15 | 15 | 15 | 18 |
5 | 0 | 0 | 3 | 3 | 3 | 12 | 12 | 15 | 15 | 15 | 15 | 18 |
total = 11 #背包能容纳的重量
n = 5 #物品的数量
w = [5,4,7,2,6] #每件物品的重量
p = [12,3,10,3,6] #每件物品的价值
rest = [[0]*(total+1) for i in range(n+1)] # 初始化一个二维数组,rest[i][w] (i=0,1,2,3,4,5 w=0,1,2,3,4,...11)
f = [0] * (total+1)
def pack():
"""
:param n: 物品的数量
:param total: 背包能容纳的重量
"""
for i in range(1, n+1):
for j in range(total+1):
if w[i-1] > j:
rest[i][j] = rest[i-1][j]
else:
if j-w[i-1] >= 0:
rest[i][j] = max(rest[i-1][j-w[i-1]]+p[i-1], rest[i-1][j])
return rest
def pack_2():
"""
优化空间复杂度之后的算法 O(total+1)
:return:
"""
for i in range(1, n+1):
for j in range(total, w[i-1]-1, -1):
f[j] = max(f[j], f[j - w[i - 1]] + p[i - 1])
return f
if __name__ == "__main__":
rest = pack()
print("rest: ", rest)
rest = pack_2()
print("pack_2: ", rest)