动态规划之-0-1背包问题及改进

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

动态规划之-0-1背包问题及改进

有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。在选择装入背包的物品时,对于每种物品i,只能选择装包或不装包,不能装入多次,也不能部分装入,因此成为0-1背包问题。

形式化描述为:给定n个物品,背包容量C >0,重量第i件物品的重量w[i]>0, 价值v[i] >0 , 1≤i≤n.要求找一n元向量(X1,X2,…,X n,), X i∈{0,1}, 使得∑(w[i] * Xi)≤C,且∑ v[i] * Xi达最大.即一个特殊的整数规划问题。

数学描述为:

求解最优值:

设最优值m(i,j)为背包容量为j、可选择物品为i,i+1,……,n时的最优值(装入包的最大价值)。所以原问题的解为m(1,C)

将原问题分解为其子结构来求解。要求原问题的解m(1,C),可从m(n,C),m(n-1,C),m(n-2,C).....来依次求解,即可装包物品分别为(物品n)、(物品n-1,n)、(物品n-2,n-1,n)、……、(物品1,物品2,……物品n-1,物品n)。最后求出的值即为最优值m(1,C)。

若求m(i,j),此时已经求出m(i+1,j),即第i+1个物品放入和不放入时这二者的最大值。

对于此时背包剩余容量j=0,1,2,3……C,分两种情况:

(1)当w[i] > j,即第i个物品重量大于背包容量j时,m(i,j)=m(i+1,j)

(2)当w[i] <= j,即第i个物品重量不大于背包容量j时,这时要判断物品i放入和不放入对m的影响。

若不放入物品i,则此时m(i,j)=m(i+1,j)

若放入物品i,此时背包

剩余容量为 j-w[i],在子结构中已求出当容量k=0,1,2……C 时的最优值m(i+1,k)。所以此时m(i,j)=m(i+1,j-w[i])+v[i]。

取上述二者的最大值,即m(i,j) = max{ m(i+1,j),m(i+1,j-w[i])+v[i] }

总结得出状态转移方程为:

该算法的python代码实现:

1 # 0-1背包问题

2__author__ = 'ice'

3

4

5 # 背包容量0~capacity,不是0~capacity-1

6def knapsack(weight, value, capacity):

7if len(weight) != len(value):

8print("parameter err!")

9return

10 obj_num = len(weight)

11 result = [[] for x in range(obj_num)]

12 divide = min(weight[-1], capacity)

13 result[-1] = [0 for x in range(divide)]

14 result[-1].extend(value[-1] for x in range(divide, capacity + 1))

15for i in reversed(list(range(1, obj_num - 1))):

16 divide = min(weight[i], capacity)

17for j in range(divide):

18 result[i].append(result[i + 1][j])

19for j in range(divide, capacity + 1):

20 result[i].append(max(result[i + 1][j], result[i + 1][j - weight[i]] + value[i]))

21

22 result[0] = {capacity: result[1][capacity]}

23if weight[0] <= capacity:

24 result[0][capacity] = max(result[1][capacity], result[1][capacity - weight[0]] + value[0])

25

26 vector = [0 for x in range(obj_num)]

27 capacity_temp = capacity

28for i in range(obj_num - 1):

29if result[i][capacity_temp] != result[i + 1][capacity_temp]:

30 vector[i] = 1

31 capacity_temp -= weight[i]

32

33if capacity_temp == 0:

34 vector[-1] = 0

35else:

36 vector[-1] = 1

37

38return {'total_value': result[0][capacity], 'select': vector}

但是,该算法有两个明显的缺点:1,基于上述代码,因为数组索引的需要,要求所给物品重量为整数。2,当背包容量C很大时,算法所需计算时间较多。当C>2^n时,需要Ω(n*2^n)计算时间。

所以,改进算法如下:

对于函数m(i,j)的值,当i确定,j为自变量时,是单调不减的跳跃式增长,如图所示。而这些跳跃点取决于在(物品i,物品i+1,……

相关文档
最新文档