0-1背包问题

xiaoxiao2021-02-28  119

今天做笔试题,看到一个用0-1背包解决的问题。

什么是背包问题?

背包问题,常见的有三种类型:基本的0-1背包、完全背包和多重背包、二维背包等。

首先是基本的0-1背包问题。因为这里的物品一般指花瓶、玉器什么的,要么拿、要么不拿,只有0和1两种状态,所以也叫0-1背包。0-1背包虽然简单,却很重要,是“万法之源”,是其他几类问题的基础。

初学者有时会认为,0-1背包可以这样求解:计算每个物品的Vi/Wi,然后依据Vi/Wi的值,对所有的物品从大到小进行排序。其实这种贪心方法是错误的。就像典型DP问题中的硬币问题(给定一定面额的硬币,让凑到某数所需最小的钱数)

动态规划

其实,0-1背包是DP的一个经典实例,可以用动态规划求解。

DP求解过程可以这样理解:对于前i件物品,背包剩余容量为j时,所取得的最大价值(此时称为状态3)只依赖于两个状态。

状态1:前i-1件物品,背包剩余容量为j。在该状态下,只要不选第i个物品,就可以转换到状态3。

状态2:前i-1件物品,背包剩余容量为j-w[i]。在该状态下,选第i个物品,也可以转换到状态3。

因为,这里要求最大价值,所以只要从状态1和状态2中选择最大价值较大的一个即可。

状态转换方程:

dp(i,j)=Max(dp(i1,j),dp(i1,jw[i])+v[i])

dp(i,j) 表示前i件物品,背包剩余容量为j时,所取得的最大价值。

python实现

# -*- coding:utf-8 -*- # author: Gao Daiheng ''' 0-1背包问题 ''' def backpag_dynamic(w, v, container, res): assert len(w) == len(v), "weight和value的尺度不同!" limits = container + 1 n = len(w) # n为6 # c[i][j]表示在前i个物体中,能够装入载重量为j的背包中的物体的最大价值 c = [[0 for j in range(limits)] for i in range(n)] for i in range(1, n): for j in range(limits): c[i][j] = c[i - 1][j] if j >= w[i] and (c[i-1][j-w[i]] + v[i]) > c[i][j]: c[i][j] = c[i-1][j-w[i]] + v[i] # 抽取位置 for i in range(n-1, 0, -1): if c[i][j] > c[i - 1][j]: res[i] = True j -= w[i] return max(c[-1]) def main(): C = 10 # 容量为10 n = 5 # 物品为5个 # 注意,务必要在v(值) 和 w(重量)前面分别加上 # 0,即子问题的形式从0开始 v = [0, 2, 4, 3, 6, 8] w = [0, 1, 5, 3, 4, 5] res = [False for i in range(n + 1)] maxv = backpag_dynamic(w, v, C, res) print('最大值为:{}'.format(maxv)) for i in range(len(res)): if res[i]: print("第{}位被抽出".format(i)) if __name__ == "__main__": main()
转载请注明原文地址: https://www.6miu.com/read-36596.html

最新回复(0)