动态规划,Dynamic Programming,python代码实现

动态规划问题

例如: 你有一个背包,最大承受重量为max_weight,有一些宠物,每个宠物有自己的重量,每个宠物能给你带来的价值不同,现在要背着宠物去旅行,目的是使价值最大化。(其他问题:例如给一定量的本金,去买房子,每个房子的售价和给你带来的收益不一样,求使收益最大化的买房策略)

宠物的重量

宠物名重量weight
cat1
bird1
dog2
tiger2
elephant3

宠物的价值

宠物名价值Value
cat3
bird6
dog5
tiger9
elephant10

先看下面的表格,第i行第j列元素表示:在背包容量为j的情况下,能选择的宠物为0-i,所能带来的最大价值
举个例子,[3][2]表示:背包容量为2,只能选cat,bird,dog这三种宠物,所带来的最大价值

宠物名/背包重量12345max_weight
cat
bird
dog
tiger
elephant

动态规划就是将物品种类和背包重量逐步增加,来求解问题。

每新增一种宠物选项i+1时,有两种情况,
一种是不选择这个宠物,则最大价值为背包重量不变的情况下,选择0-i种宠物带来的最大价值
另一种情况是,选择这种宠物i+1,则剩余空间为max_weight - weight[i+1],则最大价值为这个宠物的价值+剩余空间选择0-i种宠物带来的最大价值

取这两种情况的最大值为最终结果,

举个例子:计算[3][2]时,dog为新增宠物选项,
情况一:不选择dog,则最大价值仍然为max_weight=2时,可选项是cat,bird时的最大收益,即[2][2]
情况二:选择dog,剩余空间为max_weight-dog的weight = 0,则在剩余空间为0,可选择cat,bird时,带来的最大价值为0(这里因为没有空间了,正常是[i][max_weight-dog的weight])

不带注释的版本

import numpy as np

value_dict = {"cat":3, "bird":6, "dog":5, "tiger":9, "elephant":10}
weight_dict = {"cat":1, "bird":1, "dog":2, "tiger":2, "elephant":3}
value_list = [3, 6, 5, 9, 10]
weight_list = [1, 1, 2, 2, 3]

def dp_matric(pet_lens, max_weight, value_list, weight_list):
    max_value_matrix = np.zeros((pet_lens, max_weight), dtype=np.dtype((np.str_,500)))
    for pet_i in range(pet_lens):
        for bag_weight in range(max_weight):
            c1 = max_value_matrix[pet_i-1][bag_weight] if pet_i > 0 else 0
            weight_i = weight_list[pet_i]
            value_i = value_list[pet_i]

            if bag_weight+1 < weight_i :
                c2 = max_value_matrix[pet_i-1][bag_weight] if pet_i > 0 else 0
            else:
                resi = max_value_matrix[pet_i-1][bag_weight-weight_i] if pet_i > 0 and bag_weight-weight_i >= 0 else 0
                c2 = value_i + int(resi)
            max_value_matrix[pet_i][bag_weight] = c1 if int(c1) > int(c2) else c2
    return max_value_matrix

print(dp_matric(len(weight_dict.items()), 6, value_list, weight_list))

带注释的版本

import numpy as np

value_dict = {"cat":3, "bird":6, "dog":5, "tiger":9, "elephant":10}
weight_dict = {"cat":1, "bird":1, "dog":2, "tiger":2, "elephant":3}
value_list = [3, 6, 5, 9, 10]
weight_list = [1, 1, 2, 2, 3]

# pet_i表示宠物下标,只能选择pet_i以及pet_i之前的宠物
# bag_weight为背包容量大小
def dp_matric(pet_lens, max_weight, value_list, weight_list):
    # 初始化最大价值矩阵
    max_value_matrix = np.zeros((pet_lens, max_weight), dtype=np.dtype((np.str_,500)))
    for pet_i in range(pet_lens):
        # bag_weight的下标从0开始,但实际表示的weight是从1开始, bag_weight表示的背包容量为bag_weight+1
        for bag_weight in range(max_weight):
            # c1为不考虑pet_i的最大价值
            # 放入pet_i之前的最大价值,如果pet_i为第一个可选择的宠物,则之前的最大价值为0
            c1 = max_value_matrix[pet_i-1][bag_weight] if pet_i > 0 else 0
            # pet_i的权重和价值
            weight_i = weight_list[pet_i]
            value_i = value_list[pet_i]

            # c2为考虑pet_i的情况,又分背包能不能放下pet_i两种情况
            # 因为矩阵下标从0开始,bag_weight表示的背包容量为bag_weight+1
            if bag_weight+1 < weight_i :
                # 背包放不下pet_i
                c2 = max_value_matrix[pet_i-1][bag_weight] if pet_i > 0 else 0
            else:
                # 背包能放下pet_i
                # 放入pet_i, 最大价值=pet_i的价值+(max_weight-pet_i的weight)剩余空间的最大价值
                # resi为剩余空间的最大价值
                # 如果pet_i为第一个可选择的宠物,无论剩余空间大小为多少,没有其他宠物可选,故剩余空间的最大价值为0
                # bag_weight-weight_i代表的剩余空间大小为bag_weight-weight_i+1, 只有剩余空间>=1(即bag_weight-weight_i>=0),该空间才能有价值,否则为0
                resi = max_value_matrix[pet_i-1][bag_weight-weight_i] if pet_i > 0 and bag_weight-weight_i >= 0 else 0
                c2 = value_i + int(resi)
            max_value_matrix[pet_i][bag_weight] = c1 if int(c1) > int(c2) else c2
    return max_value_matrix

# max_value_matrix[i][j]表示空间大小为j+1,能取的物品为value_list[0:i],  所能取到的最大价值
print(dp_matric(len(weight_dict.items()), 6, value_list, weight_list))


背包容量为6时的最大价值矩阵如下:
在这里插入图片描述
如果宠物的顺序改变,中间的生成过程会不同,但最后的结果是一样的
一般要求的是最终结果,即图中的25

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值