python 01背包问题(详细注释)

01背包问题是背包问题中的较简单情况。假定一背包和若干物品,物品总体积超过背包容量。已知背包容量,已知各物品的体积和价值,要求选取若干物品放入背包,使放入物品总价值最大。
通常用动态规划解决,列状态转移方程,画状态转移矩阵。

首先定义01背包函数。输入中,p为顺次表示物品价值的列表,w为顺次表示物品体积的列表;v为背包容量。

def knapsack(p, w, v):
    #n来存储物件的总数目
    n = len(p)
    #lists存储应该放入背包的物品,arr为状态转移矩阵,它有v+1列,n+1行。
    #arr[0][0]表示在0件物品可选,选入物品体积总和不超过0的状态下,做出最优选择时放入物品的最大价值。
    #arr[i][j]表示在可选前i个物品,选入物品体积总和不超j的状态下,做出最优选择时放入物品的最大价值。
    lists,arr = [],[[0] * (v + 1) for _ in range(n + 1)]
    #从第1个到第n个物件
    for i in range(1, n + 1):
        #对每一种背包限容可能
        for j in range(1, v + 1):
            #当前物品体积比限容大,则不可选这个物品。
            #若当前物件体积比当前限容小
            if w[i - 1] <= j:  
                # p[i-1]为当前物品价值,w[i-1]为当前物品体积,现对当前物品是否放入进行决策
                #研究第i个物品时,根据循环顺序,上面的行已被填满。也即前i-1件物品可选时,任一限容下的最优价值已知。
                #第i个物品无非有选和不选两种情况。
                #若选第i件物品,说明可能第i件物品价值高,舍弃之前中的某些件物品选上它得到的总价值更高(也有未舍弃的可能)
                #若不选第i件,说明可能以前有某物品价值太高但占一些体积,如果选上第i件就装不下了,舍弃已选物品又得不偿失。
                #选择第i件对应的总价值,
                #是第i件物品价值加上限选前i-1件、以当前研究状态容量减去第i个物品体积所得的数为可容纳最大总体积的那个状态。
                #不选第i件对应的物品总价值显然与相同限容下可选前i-1件得到的最优价值相同。
                #两者取较大值,便是该状态(可选前i件、限容为j)对应的最大价值
                arr[i][j] = max(arr[i - 1][j], p[i - 1] + arr[i - 1][j - w[i - 1]])
            #当前物品超过当前背包限容,就和可选前i-1件物品时的最大价值相等
            else: 
                arr[i][j] = arr[i - 1][j]

现在,矩阵已经建成。但要将所选物品对应下标输出,需要更多操作。


    #输出选择结果
 
    #将背包容量赋给remain
    remain = v
    #从下标为i的最后一个物品开始寻找。从前往后找找到的很可能不是最优解。(思考原因)
    for i in range(n, 0, -1):
        #如果选择了第i个物品,那么第i行某列的最大价值(也就是那个位置存储的元素)一定比同一列上一行对应的最大价值大(思考相等的可能,这里不讨论)
        #最优解中,在原来的排序中下标最大的物品一定锁定在矩阵的最后一列寻找。
        #在最后一列,从下至上,如果第i行元素比第i-1行元素大,说明最后一步选择的是第i件物品。
        #为了找到最优解中下标倒数第二的物品,应该从第i-1行向上寻找。
        #这时,问题缩小为在【可选前i-1件物品,总体积不超过背包原容量减去第i件物品体积】这种条件下寻找最优解
        #所以最优解中下标倒数第二的物品在列数为【总列数减去第i件物品体积所得到的数】,行数为i-1中寻找即可。
        #以此类推,直至从最后一个物品判断到第一个结束
        if arr[i][remain] > arr[i - 1][remain]:
            lists.append(i)  # i为当前物品的编号
            remain -= w[i - 1]  # 容积减去已经找到的物品,再次寻找
    
    #矩阵的右下角的元素就是最大价值
    print(arr[-1][-1])
    #由于从后往前依次加入的最优解,最好倒序输出
    for i in range(len(lists)):
        print(lists[len(lists) - i-1],end = ' ')

测试:

a = int(input())#此参数未用到
v = int(input())#背包容量
w = list(map(int,input().split()))#物品体积
p = list(map(int,input().split()))#物品价值
knapsack(p,w,v)

在这里插入图片描述

发布了12 篇原创文章 · 获赞 1 · 访问量 899

猜你喜欢

转载自blog.csdn.net/Wang_Runlin/article/details/104654548
今日推荐