01背包问题二维数组和一维数组间的区别

发布于:2025-04-02 ⋅ 阅读:(17) ⋅ 点赞:(0)

题目链接:01背包

        有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次第 i 件物品的体积是 vi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。

这篇文章主要跟大家讲解:二维数组和一维数组解决01背包问题的区别

关于二维数组的详细图文讲解,我之前写过一篇文章,大家可以去看看二维数组解决01背包问题

下面先给出二维数组解决“01背包”问题的模板:

for(int i = 1;i <= n;i++){  //动态规划--二维数组
    for(int j = 0;j <= m;j++){
        if(v[i] <= j){
            f[i][j] = max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
        }
    }
}

再给出一维数组解决“01背包”问题的模板:

for (int i = 0; i < M; ++i) {  动态规划--一维数组
    for (int j = N; j >= costs[i]; --j) {
        dp[j] = max(dp[j], dp[j - costs[i]] + values[i]);
    }
}

大家对比上面的代码可以发现:

1.二维数组和一维数组都需要两层for循环分别遍历物品和背包。其中二维数组的两层for循环可以改变顺序(即先遍历背包再遍历物品),但一维数组必须先遍历物品再遍历背包。接下来详细讲一下对于二维数组,无论是先遍历背包还是先遍历物品,只是从横着修改数组的元素变成了竖着修改。当前的值依赖于二维数组左上角部分的值,所以对它没有影响。那么对于一维数组而言,如果变成先遍历背包再遍历物品,背包容量为 j 的时候,能放哪个物品已经被确定了,并且此时背包只能存放一个物品,相当于筛选了当前背包容量能存放哪一个物品的价值最大,完全不涉及动态规划,因为要依赖于它前面的值,但它前面的值全部都还没有被修改。

2.一维数组for循环遍历背包容量时,必须从大到小。这是因为我们在改变 dp[j] 时,依赖于它前面的元素,而从小到大遍历书包容量时,前面的元素已经被修改,所以会导致出错(一个物品不止一次被加入背包中)。而我们从大到小遍历书包容量就可以完美避开这个问题。那为什么又说二维数组既可以从小到大遍历又可以从大到小遍历呢?这是因为关于物品 i - 1 的所有值已经被保存下来了,不会被修改。

3.对于for循环遍历背包容量时,一维数组从大到小,并且 j >= weight[i] 。这里很容易理解,因为当 j < weight[i] 时,背包无法放入当前物品,所以一维数组的值不会被修改。只有在 j >= weight[i] 时才会修改。其实和二维数组的逻辑是一样的,只是少写了一个 if ... else ...判断语句。