[python] 动态规划求解背包问题

                                      动态规划求解01背包

 

01背包问题描述:

01背包问题可以假设为现在有一堆物品,每一个物品都具有两个属性,物品的重量和价值。现在有一个承重有限的背包,给定背包的最大承受重量。现在要将物品装入背包,使得背包里所有物品的价值总和最大,我们应该放哪些物品进入背包。

 动态规划

动态规划算法通常所用于求解具有某种最有性质的问题。在某一个具体的问题中,可能会存在很多可行解,而我们所需要的就是去寻找这众多可行解中的最优解。动态规划的思想也和分治算法的思想类似,动态规划算法也是将原问题分解为若干个子问题,然后根据子问题的解来得到原问题的最优解。动态规划算法和分治法不同的是,分治法分解得到的若干个子问题是互相独立的,相互没有约束。而动态规划算法得到的子问题的解之间相互约束,从规模最小的子问题到原问题中的每一级,较高级的子问题的解是由较低级的子问题的最优解得到的,这样保证了每一级所得到的解都是当前子问题的最优解。最终得到的原问题的解也便是最优的。但动态规划算法只能得到最优解中的某一个,而不能得到所有的最优解。

具体步骤:

(1) 把原问题分解成各个子问题,如背包的重量为i(0<=i<=背包最大承重)时,面对前j(1<=j<=n)件物品时,背包所能获取的最大价值。

(2) 依次求出每个子问题的最优解,并且每一个问题的最优解都是由前一个问题的最优解得到,找到其状态转移方程。

(3) 最终通过各个子问题的最优解得到原问题的最优解。

关键代码思想:

(1) 初始化部分将输入的物品的重量和价值分别用一个列表来储存,采用split()函数以“ ”为界限划分,再将其中的每一个元素转化为int型,append到value[]和weight[]列表中。

(2) 设置一个二维数组来保存当面对前i件物品时,背包承重为j时,背包所能获得的最大价值。python中的二维数组用列表生成式来定义,max_value = [[0]*(bag_weight+1) for i in range(0,n+1)],创建一个长度为n+1的列表,并且里面的每个元素也均为列表,且长度均为bag_weight+1,并且将其全部赋初值为0。

(3) 求取状态转移方程,当面对第i个物品时,背包承重j所能获得的最大价值为当面对第i-1个物品时背包承重为j的最大价值或者为第i个物品腾出空间,获得价值为面对前i-1个物品时,背包承重为j-weight[i]时的最大价值加上第i件物品的价值。因此得到的状态转移方程为:

if(j>=weight[i]):

              max_value[i][j] = max(max_value[i-1][j], max_value[i-1][j-weight[i]]+value[i])

else:

              max_value[i][j] = max_value[i-1][j]

(4)接下来判断背包承重为bag_weight时,重新定义一个列表来保存所拿的物品(拿了为1,没拿为0),将max_value[][bag_weight]从后往前比较,若此时的max_value与前一个值相等的话,则证明此件物品没有拿,如果不相同,则证明拿了此件物品,并且将bag_weight减去该物品的质量,继续上述过程。

(5) 计算程序运行的时间,导入time模块,用该模块中的clock函数标记程序输入完成后开始的时间和最后输出结果后的时间,将两个时间进行做差值来计算程序运行的时间。

实例解析:

物品数量:7

每件物品价值:5   4   7   6   5   8   4

每件物品质量:1   3   2   4   5   3   2

背包最大承重:13

根据以上思路便能得到一下表格,横轴坐标为面对第i(i从0到7)件物品,纵轴坐标为背包承重为j(j从0到13)时,背包所对应的最大价值。

0 1 2 3 4 5 6 7 8 9 10 11 12 13
1 5 5 5 5 5 5 5 5 5 5 5 5 5
2 5 5 5 9 9 9 9 9 9 9 9 9 9
3 5 7 12 12 12 16 16 16 16 16 16 16 16
4 5 7 12 12 12 16 18 18 18 22 22 22 22
5 5 7 12 12 12 16 18 18 18 22 22 23 23
6 5 7 12 13 15 20 20 20 24 26 26 26 30
7 5 7 12 13 16 20 20 24 24 24 28 30 30

具体代码的实现:

import time

def main():
    print("请输入一共有多少个物品:",end = " ")
    n = int(input())
    value = []
    value.append(0)
    weight = []
    weight.append(0)
    print("请输入每个物品的价值:",end = " ")
    value_all = input().split(" ")
    for value_one in value_all:
        value.append(int(value_one))
    print("请输入每个物品的重量:",end = " ")
    weight_all = input().split(" ")
    for weight_one in weight_all:
        weight.append(int(weight_one))
    print("请输入背包重量:",end = " ")
    bag_weight = int(input())

    time1 = float(time.clock())#保存程序开始时的时间
    max_value = [([0]*(bag_weight+1)) for i in range(0,n+1)]
    for i in range(1,n+1):
        for j in range(1,bag_weight+1):
            if(j>=weight[i]):
                max_value[i][j] = max(max_value[i-1][j],max_value[i-1][j-weight[i]]+value[i])
            else:
                max_value[i][j] = max_value[i-1][j]
    print("当背包重量为%d时,能拿物品的最大价值为:%d"%(bag_weight,max_value[n][bag_weight]))
    item = [0 for i in range(n+2)]
    m = n
    while m>=1:
        i = m
        if(max_value[i][bag_weight] == max_value[i-1][bag_weight]):
            item[i] = 0
        else:
            item[i] = 1
            bag_weight-=weight[i]
        m-=1
    print("所能拿的物品为(1为拿,0为不拿):",end = " ")
    for i in range(1,n+1):
        print(item[i],end = " ")
    time2 = float(time.clock())
    print("\n程序运行时间:%f"%(time2-time1))

if __name__ == '__main__':
    main()

测试记录:

注意事项:

物品价值和重量输入的时候,每一个元素之间有且只有一个空格隔开,并且行末不能存在空格。

 

 

猜你喜欢

转载自blog.csdn.net/qq_40102757/article/details/81607135