揹包问题之动态规划(Dynamic Programming)问题Python实现

动态规划问题

动态规划问题,想法其实很简单,就是根据贝尔曼最优性原理来求解。
如下图:
在这里插入图片描述
简单理解:假设图中ABⅡC是最优的轨迹,那么,BⅡC一定是最优的轨迹。这一点应该很容易理解。
证明:假设BⅠC比BⅡC更优,那么AC的最优轨迹就应该为ABⅠC。矛盾。

揹包问题

考虑一个场景:当你有去沙漠旅行,你有一个揹包和一些物品,揹包有最大承受重量,物品也有重量和价值,而物品种类很多,不可能全都装在揹包里,如何去选取价值总量最高的物品组合呢?

物品价值表

物品名 价值
water 10
book 3
food 9
jacket 5
camera 6

物品重量表

物品名 重量
water 3kg
book 1kg
food 2kg
jacket 2kg
camera 1kg

考虑使用贪婪算法,那就是什么价值高就优先拿什么,但有时这种近似解会不准,这时就要采用动态规划方法:从小问题入手,逐步解决大问题,可以帮助你在给定约束条件下找到最优解

思路

对揹包容量,从装满到全空,进行迭代。每次都将剩余的空间装入价值最大的物品。迭代完成后,即得到最优解。
伪代码如下:

for 当前剩余质量 in range(1, 揹包最大质量)for 小于当前剩余质量的最优解:
		for 物品 in 物品列表:
			if 物品没有被小于当前剩余质量的最优解选中 and 物品质量 小于等于 (当前剩余质量 - 小于当剩余质量的最优解所使用的质量):
				将该物品放入揹包,并且统计揹包的总价值
		遍历了物品列表,选出加入了一件新物品后的最优解,即价值最大的
	遍历所有小于当前剩余质量最优解后,在上一步价值最大的中选择价值最大的,成为新一步的最优解。

talk is cheap, show me the code

#########################################################################
#                      Dynamic Programming
#                           求解揹包问题
#########################################################################

# 物品信息,包含物品质量mass和物品价值value
goods = {
    "water": { "mass": 3, "value": 10 },
    "book": { "mass": 1, "value": 3 },
    "food": { "mass": 2, "value": 9 },
    "jacket": { "mass": 2, "value": 5 },
    "camera": { "mass": 1, "value": 6 }
}

# 揹包容量
package_size = 6

"""
动态规划问题,根据贝尔曼最优性原理,考虑揹包剩余容量,保证揹包剩余容量装的物品价值最大。
当揹包剩余容量从0开始循环到揹包最大容量时,即最优解。
"""

# 揹包中各种剩余容量的最优解, ["camera", "food", "book", 18],最后一个值表示总价值
optimal_answers = []
optimal_answers.append([0])   # 将剩余容量为0时最优解加入最优解列表

for remaining_size in range(1, package_size+1):
    temps = []
    for i in range(len(optimal_answers)):    
    # 此处i可以改进,不用每次都从0开始,可以以满足没有装入揹包得物品得最大质量 等于 remaining_size - i为条件
        # 对相同的remaining_size - i,选取最优的
        temp = []
        for good in goods:
            # 如果该商品没有放入包里,且商品的质量小于等于remaining_size - i,则将其放入揹包内
            # print(good, ":", goods[good])
            if not (good in optimal_answers[i]) and (remaining_size - i) >= goods[good]["mass"]:
                opt_ans = optimal_answers[i][:]
                # print(optimal_answers[i])
                # print("opt_ans-optimal_answer:", opt_ans)
                opt_ans.insert(-1, good)
                opt_ans[-1] += goods[good]["value"]
                # print("opt_ans:", opt_ans)
                temp.append(opt_ans)
        
        # print("temp:", temp)
        max_value = 0
        optimal_item = None
        for item in temp:
            # print("item:", item)
            if item[-1] > max_value:
                max_value = item[-1]
                optimal_item = item
        if optimal_item != None:
            temps.append(optimal_item)

    max_values = 0
    optimal_items = None
    # print("temps:", temps)
    for item in temps:
        # print("items:", item)
        if item[-1] > max_values:
            max_values = item[-1]
            optimal_items = item

    optimal_answers.append(optimal_items)
    # print("optimal_answers:", optimal_answers)


print("揹包问题最优解为:\n揹包的装法:", optimal_answers[-1][:-1], "\n揹包的总价值为:", optimal_answers[-1][-1])
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章