lotus

贵有恒何必三更眠五更起 最无益只怕一日曝十日寒

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 

1.  01背包:二维朴素写法

 

public static int getMaxValue(int[] weight, int[] values, int w) {

int n = weight.length;
int[][] dp = new int[n + 1][w + 1];

for (int i = 1; i <= n; i++) {
for (int j = 1; j <= w; j++) {
if (j >= weight[i - 1]) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + values[i - 1]);
}
}
}

return dp[n][w];
}

2.  01背包:二维朴素写法 —> 一维空间优化写法

 

public static int getMaxValue2(int[] weight, int[] values, int w) {
int n = weight.length;

int[] dp = new int[w + 1];
for (int i = 1; i <= n; i++) {
for (int j = w; j >= weight[i-1]; j--) {
if (j >= weight[i - 1]) {
dp[j] = Math.max(dp[j], dp[j - weight[i - 1]] + values[i - 1]);
}
}
}

return dp[w];
}

3.  以上二维转一维 两个重点问题

3.1  为何可以用一维数组代替二维数组?

二维数组更新方式为

f[i][j] = f[i - 1][j] # 不含i的所有选法的最大价值
if j >= v[i]: # 判断含i的选法是否成立
f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i])


可以看出f[i][:]只依赖于f[i-1][:],所以根本没必要保留之前的f[i-2][:]等状态值;

使得空间从o(n*m)缩小到o(m),n,m分别为物品个数和背包体积
其实每个物品的体积和价值在该层循环结束后也不会再用上,这里也可以压缩为两个o(1)的空间

 

3.2 、为何要逆序更新?


一维数组更新方式为

while j >= v[i]:
dp[j] = max(dp[j], dp[j - v[i]] + w[i])


我们只有上一层dp值的一维数组,更新dp值只能原地滚动更改;


注意到,

当我们更新索引值较大的dp值时,需要用到索引值较小的上一层dp值dp[j - v[i]];
也就是说,在更新索引值较大的dp值之前,索引值较小的上一层dp值必须还在,还没被更新;
所以只能索引从大到小更新。

 

 4.  两种写法的动态规划求解过程

4.1  二维动态规划 过程 

例如,假设有5个物品,它们的重量和价值分别为:

物品编号重量价值
1 2 3
2 3 4
3 4 5
4 5 6
5 9 10
如果背包的容量为8,那么最优的方案是装入物品2和物品4,它们的总重量为8,总价值为10。

填写动态规划表:按照递推关系,从左到右,从上到下依次计算f [i] [j]的值,并记录在表格中。例如,对于上面给出的例子,动态规划表如下:

容量 012345678
f[0] 前0个元素最大价值 0 0 0 0 0 0 0 0 0
f[1] 前1个元素最大价值 0 0 3 3 3 3 3 3 3
f[2] 前2个元素最大价值 0 0 3 4 4 7 7 7 7
f[3] 前3个元素最大价值 0 0 3 4 4 7 8 9 9
f[4] 前4个元素最大价值 0 0 3 4 5 7 8 9 10
f[5] 前5个元素最大价值 0 0 3 4 5 7 8 9 10

 

 

4.2  一维动态规划过程

看上面这段话是不是理解起来比较难,那我们 模拟一遍  逆序的过程  一切疑问皆明了

 

posted on 2023-07-06 18:55  白露~  阅读(6)  评论(0编辑  收藏  举报