动态规划解决背包问题的方法(动态规划之0-1背包问题优化)

上篇文章中,讲述了动态规划之0-1背包问题及其解决方法。它的时间复杂度和空间复杂度都为:O(n * C), 其中n为物品个数; C为背包容积。

在时间复杂度方面已经达到了最优,但是空间复杂度方面还是可以进行优化的。下面将说明如何优化。

在上篇文章,其记忆化搜索的数组定义为:

memo[i,j] 表示在前i件(包括i件)物品中选择若干件放在承重为 j 的背包中,可以取得的最大价值。

一、只用二行的空间

根据它的状态转移方程:

这时要求解的问题可以化解为求下面2个问题的最大值

(1)第i个物品不放进背包里,这时的价值就是i-1时的价值:F(i-1,c)

(2)如果第i个可以放入来,且不超过容量C,这是的价值为第i个物品的价值加上前面i-1的价值,注意这时i-1的重量为c-w(i):v(i) F(i-1, c-w(i) )

真正影响结果的只是当前行与前一行的数据,因此可以用行数 i%2 的值来作为保存的行,奇数行或者偶数行。

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(1)

行数的变化为:

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(2)

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(3)

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(4)

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(5)

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(6)

千言万语还不如直接看代码来得实际。

看其实现:

/// 背包问题 /// 动态规划改进: 滚动数组 /// 时间复杂度: O(n * C) 其中n为物品个数; C为背包容积 /// 空间复杂度: O(C), 实际使用了2*C的额外空间 public class Solution1 { public int knapsack01(int[] w, int[] v, int C){ if(w == null || v == null || w.length != v.length) throw new IllegalArgumentException("Invalid w or v"); if(C < 0) throw new IllegalArgumentException("C must be greater or equal to zero."); int n = w.length; if(n == 0 || C == 0) return 0; int[][] memo = new int[2][C 1]; for(int j = 0 ; j <= C ; j ) memo[0][j] = (j >= w[0] ? v[0] : 0); // 变化的地方加入% for(int i = 1 ; i < n ; i ) for(int j = 0 ; j <= C ; j ){ memo[i % 2][j] = memo[(i-1) % 2][j]; if(j >= w[i]) memo[i % 2][j] = Math.max(memo[i % 2][j], v[i] memo[(i-1) % 2][j - w[i]]); } return memo[(n-1) % 2][C]; } public static void main(String[] args) { } }

需要的存储长度只为2(C 1),此时空间复杂为O(C)

二、只用一行的空间

因为当前行都是在上一行的基础上比较计算得到的,因此可以将每次的计算结果直接放到上一层的方格里。

1、刚刚开始,除了第一个外,其它的都是6

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(7)

2、当把id为1的物品放入进行计算时,从最后一个往回计算容量为5为,原来的6与10 6=16作比较,所以容量为5的位置修改为16

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(8)

3、id为1的物品,移动为容量为4的元素时,是容量为2与容量为4的作比较

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(9)

4、这时也是用16替换

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(10)

5、再往回移动比较1和3,一样的用16替换

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(11)

6、一样再往移动比较0和2的元素,这时会有不同

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(12)

7、因为容量只有2,所以只能放下10的价值,比6大,替换为10

动态规划解决背包问题的方法(动态规划之0-1背包问题优化)(13)

8、具体的代码实现如下

因为长度只为C 1,所以不再需要二维数,只用一维数据存储结果的缓存就可以。

/// 背包问题 /// 动态规划改进 /// 时间复杂度: O(n * C) 其中n为物品个数; C为背包容积 /// 空间复杂度: O(C), 只使用了C的额外空间 public class Solution2 { public int knapsack01(int[] w, int[] v, int C){ if(w == null || v == null || w.length != v.length) throw new IllegalArgumentException("Invalid w or v"); if(C < 0) throw new IllegalArgumentException("C must be greater or equal to zero."); int n = w.length; if(n == 0 || C == 0) return 0; int[] memo = new int[C 1]; for(int j = 0 ; j <= C ; j ) memo[j] = (j >= w[0] ? v[0] : 0); for(int i = 1 ; i < n ; i ) for(int j = C ; j >= w[i] ; j --) memo[j] = Math.max(memo[j], v[i] memo[j - w[i]]); return memo[C]; } public static void main(String[] args) { } }

需要的存储长度只为C 1,此时空间复杂为O(C)

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页