这个是新学的动态规划问题中,经典的0-1背包问题。最主要的问题是清楚状态转移方程的使用方法,以及在索引时初始化的问题。(0-1背包,每个物体只能选一次,能多次选的是完全背包)
c = 10 #背包容量
w = [3,4,5,7] #物体体积
v = [1,5,6,9] #物体的价值
n = len(w)
dp = [[0 for i in range(c+1)]for j in range(1+n)] #创建一个n*c的零矩阵
w.insert(0,0) #因为dp表上次和左侧各有一列0,为了索引对齐
v.insert(0,0) #在0位置加个0,相当于在v的0位置加个0 ,即1前加0
for i in range(1,n+1):
for j in range(1,c+1):
if w[i] <= j: #物体体积小于背包体积时,有两种情况:
#要么是前一个装完最大,要么是装完现在这个还可以装其他的。
dp[i][j] = max (dp[i-1][j],dp[i-1][j-w[i]] + v[i])
else:
dp[i][j] = dp[i-1][j]
print("最大价值为",dp[n][c])
接下来是0-1背包问题从二维压缩到一维,其实是因为我们从后往前计算可行,我们只用到前一行的数,并不会改变我们改行前面的数,因此我们可以进行迭代,达到节约空间的效果。
c = 10 #背包容量
w = [3,4,5,7] #物体体积
v = [1,5,6,9] #物体的价值
n = len(w)
dp = [0 for i in range(c+1)]
w.insert(0,0) #因为dp表上次和左侧各有一列0,为了索引对齐
v.insert(0,0) #在0位置加个0,相当于在v的0位置加个0 ,即1前加0
print(dp)
for i in range(1,n+1):
for j in range(c,0,-1): #从后往前算
if w[i] <= j: #物体体积小于背包体积时
dp[j] = max (dp[j],dp[j-w[i]] + v[i])
print(w[i],j)#逐次输入,方便观看每次的结果
print(dp)
print("最大价值为",dp[c])
那我们实现完了这个问题之后,我们知道,因为只知道其价值,而不知道怎么拿物品是没有用的,所以我们现在就基于在知道物品价值的前提之下,来给出挑选物品的选择最优。
c = 10 #背包容量
w = [3,4,5,7] #物体体积
v = [1,5,6,9] #物体的价值
n = len(w)
dp = [[0 for i in range(c+1)]for j in range(1+n)] #创建一个n*c的零矩阵
w.insert(0,0) #因为dp表上次和左侧各有一列0,为了索引对齐
v.insert(0,0) #在0位置加个0,相当于在v的0位置加个0 ,即1前加0
for i in range(1,n+1):
for j in range(1,c+1):
if w[i] <= j: #物体体积小于背包体积时,有两种情况:
#要么是前一个装完最大,要么是装完现在这个还可以装其他的。
dp[i][j] = max (dp[i-1][j],dp[i-1][j-w[i]] + v[i])
else:
dp[i][j] = dp[i-1][j]
print("最大价值为",dp[n][c])
def get_path(dp,w,c):
i = len(w)-1 #选中的物体
j = c #背包的容量
res = []
while i != 0 and j != 0: #上面的dp表0行和0列都等于0,所以我们只要索引到它即可
if dp[i][j] == dp[i-1][j]:
i -= 1
else:
res.append(i-1) #上边w,v都加了0,索引的时候减一,不然会出现0,会误导结果
j -= w[i] #背包面积减去装的物体,得到那时的背包体积
i -= 1
res.sort()
return res
print("背包物品索引为",get_path(dp,w,c))