实验内容
给定几组数据,利用动态规划算法的思想,把 0-1 背包装满并使得其价值最 大。
实验原理
动态规划通过拆分问题,将问题拆分成许多的子问题,定义问题状态和状态之间的关系(即状态转移方程或递推公式),使得问题能够以递推(或者说分治) 的方式去解决。按顺序求解子问题,前一子问题的解,为后一子问题的求解提供了有用的信息,在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,那么最后一个子问题就是初始问题的解。
实验步骤
① 把问题分解成若干个子问题,如背包仅可以容纳 1 个物品且可以容纳的质量为一等。
② 依次求出各个子问题的最优解。
③ 每个子问题的最优解又可以从它的子问题的最优解中得到。
④ 通过各个子问题的最优解得到原问题的最优解
代码实现
backpack函数:
weight 表示背包能容纳的商品最大重量,number 表示商品数量,w 数组和 v 数组表示每件商品的重量以及对应的价值。首先初始化二维数组为 0,最后循环将数组中的每个元素进行填充:如果当前背包可容纳的重量小于当前商品的重量,那么背包中的总价值不会变化,否则,可以选择装下当前这件物品或者不装下这件物品,这就可以得到两个价值,那么其中最高的价值就是当前情况下背包能获得的最大价值。
main 函数中最后的两个for循环(用于找到选择的物品):
首先初始化一个 item 数组并全初始化为 0,然后循环遍历动态规划得到的数组,如果 result[i][j] > result[i-1][j],那么说明第 i-1 件物品肯定被选择了,那么 就将 item[i-1]设置为 1,循环结束后将 item 中为 1 的索引输出即可。
import time
def backpack(number, weight, w, v):
#初始化二维数组,用于记录背包中个数为i,重量为j时能获得的最大价值
result = [[0 for i in range(weight+1)] for i in range(number+1)]
#循环将数组进行填充
for i in range(1, number+1):
for j in range(1, weight+1):
if j < w[i-1]:
result[i][j] = result[i-1][j]
else:
result[i][j] = max(result[i-1][j], result[i-1][j-w[i-1]] + v[i-1])
return result
def main():
number = 5
weight = 10
w = [2, 2, 6, 5, 4]
v = [6, 3, 5, 4, 6]
start = time.time()
result = backpack(number, weight, w, v)
end = time.time()
print("共耗时:\n" + str(end - start) + " s")
print("最优解为:" + str(result[number][weight]) + "\n")
print("所选取的物品为:")
item = [0 for i in range(number+1)]
j = weight
for i in range(1, number+1):
if result[i][j] > result[i-1][j]:
item[i-1] = 1
j -= w[i-1]
for i in range(number):
if item[i] == 1:
print("第" + str(i+1) + "件")
if __name__ == '__main__':
main()
时间复杂度分析
时间消耗最大的部分就在 backpack 函数部分,而在该函数中时间消耗最大的部分又在最后的双重 for 循环中,双重 for 循环的时间复杂度即为 O(number * weight),那么整个算法的时间复杂度也是 O(number * weight)
运行结果
共耗时:
0.0 s
最优解为:15
所选取的物品为:
第1件
第2件
第5件