1、算法思想
- 假设有四个物品,如下图,背包总容量为8,求背包装入哪些物品时累计的价值最多。
- 我们使用动态规划来解决这个问题,首先使用一个表格来模拟整个算法的过程。
- 表格中的信息表示指定情况下能产生的最大价值。例如,(4, 8)表示在背包容量为8的情况下,前四个物品的最佳组合所能累计的最大价值。
- 【注】第一行全0,因为第一行考虑的是前0个物品的最佳组合,也就是没有物品,它存在的意义是方便后续计算;第一列全0,因为第一列背包容量为0,不能放入任何物品,所以价值为0。
- 表格中的信息表示指定情况下能产生的最大价值。例如,(4, 8)表示在背包容量为8的情况下,前四个物品的最佳组合所能累计的最大价值。
- 现在我们需要一步一步将这个表格填好。
-
考虑(1, 1)
- 表示前1个物品在背包容量为1的情况下,能装入背包的最佳组合所能累计的最大价值为多少。
- 已知,1号物品体积为2,价值为3。不能装入背包中,所以此时能产生的最大价值应该和前0个物品的一致,也就是0。
-
考虑(1, 2)
- 此时背包容量为2,前1个物品也就是1号物品刚好可以装入。那么需要考虑要不要将该物品装入背包。
- 如果不装,那么此时的价值应该和前0个物品的一致,也就是0。
- 如果装,那么此时的价值应该是该商品的价值+剩余容量所能装入的最大价值(前0个商品,2-2=0个容量),也就是3+0=3。
- 然后把第二行填完,即后面都为3,因为只有第一个商品。
-
2号商品体积为3,价值为4。第三行的前三列(前2个物品,容量2以内)因为不能放入2号商品,所以最大价值与前1个物品一致。
-
考虑(2, 3)
- 背包容量为3,可以放下2号物品。那么考虑要不要将该物品装入背包。
- 如果不装,那么此时的价值应该和前1个物品的一致,为3。
- 如果装,那么此时的价值应该是该商品的价值+剩余容量所能装入的最大价值(前1个商品,3-3=0个容量),也就是4+0=4。
- 后面的就不再赘述,最终得到下面的表。而(4, 8)就是所能累计的最大价值。
- 归纳
- 如果装不下当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是一样的。
- 如果装得下当前物品(选取假设1和假设2中较大的价值,为当前最佳组合的价值)
- 假设1:装当前物品,在给当前物品预留了相应空间的情况下,前n-1个物品的最佳组合加上当前物品的价值就是总价值。
- 假设2:不装当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是一样的。
- 虽然得到了在指定条件下,背包能装入的最大价值,但是还不知道背包中到底装了哪些物品。
- 接下来就需要进行回溯,查看每种情况下背包所装入的物品。
- 从后往前看,(4, 8)的价值为10,考虑有没有把4号商品装入背包中。
- 如果4号商品没有装入背包中,那么此时的价值应该和前3个商品的一致,即为9,所以4号商品是装入了背包的。
- 减去4号商品的体积,剩下3个容量。接下来就只需要看前3个商品,容量为3的情况,即(3, 3)。
- (3, 3)的体积为4,考虑有没有把3号商品装入背包中。因为此时的价值与前2个商品的一致,所以3号商品没有装入背包中。
- 剩余体积不变,继续考虑前2个商品,也就是(3, 2)。
- (3, 2)的体积为3,考虑有没有把2号商品装入背包中。因为此时的价值与前1个商品的不一致,所以2号商品是装入了背包的。
- 减去2号商品的体积,剩下0个容量。没办法装入其他的商品了,到此结束。
- 所以,当2号商品和4号商品装入背包时,能产生最大价值。
- 归纳
- 从表的右下角开始回溯,如果发现前n个物品最佳组合的价值和前n-1个物品最佳组合的价值一样,说明第n个物品没有被装入;否则,第n个物品被装入。
2、实例
- 采用动态规划算法求解01背包问题,背包体积为100,商品体积和价格如下表:
- python代码
-
# 求最大价值 def max_values(goods, bag_size, goods_num): # 创建一个二维数组来存放最大价值,100个体积,16个商品,17行,101列(保留一列为全0) values = [[i for i in range(bag_size + 1)] for i in range(goods_num + 1)] # 计算每种情况下的最大价值 for i in range(1, goods_num + 1): for j in range(1, bag_size + 1): if goods[i][0] <= j: # 商品体积小于等于背包容量 # 比较放入该商品和不放入该商品产生的最大价值 values[i][j] = max(values[i - 1][j], goods[i][1] + values[i - 1][j - goods[i][0]]) else: # 商品不能放入背包,此时最大价值等于前i-1个商品的最大价值 values[i][j] = values[i - 1][j] return values # 回溯,求哪些商品装入了背包 def search_goods(goods, values, bag_size, goods_num): good = [] i = goods_num j = bag_size while values[i][j] != 0: if values[i][j] != values[i - 1][j]: # 如果发现前n个物品最佳组合的价值和前n-1个物品最佳组合的价值不一样,说明第n个物品被装入了背包 good.append(i) j -= goods[i][1] # 减去该商品的体积 i -= 1 else: # 第n个物品没有被装入 i -= 1 return good if __name__ == '__main__': # 共有16个商品,商品的体积和价格 goods = [[0, 0], [5, 6], [8, 3], [28, 19], [9, 20], [6, 15], [18, 12], [21, 10], [19, 22], [19, 8], [23, 18], [10, 14], [9, 13], [34, 18], [26, 19], [38, 33], [9, 10]] bag_size = 100 # 背包体积 goods_num = 16 # 商品数量 # price = [5, 8, 28, 9, 6, 18, 21, 19, 19, 23, 10, 9, 34, 26, 38, 9] # volume = [6, 3, 19, 20, 15, 12, 10, 22, 8, 18, 14, 13, 18, 19, 33, 10] values = max_values(goods, bag_size, goods_num) for i in range(goods_num + 1): # 打印列表 print(values[i]) good = search_goods(goods, values, bag_size, goods_num) print("产生的最大价值为:", values[goods_num][bag_size]) print("放入背包的商品为:", good)
-
- 运行结果
文章来源地址https://www.toymoban.com/news/detail-758720.html
文章来源:https://www.toymoban.com/news/detail-758720.html
到了这里,关于算法分析与设计——动态规划求解01背包问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!