0-1 背包问题 - 求装入背包中的所有物品的最大价值

题目

一个背包有一定的承重 W,有 N 件物品,每件都有自己的价值,记录在数组 v 中,也都有自己的重量,记录在数组 w 中,每件物品只能选择要装入背包还是不装入背包,要求在不超过背包承重的前提下,选出物品的总价值最大。

思路

假设物品编号从 1 到 n,一件一件物品考虑是否加入背包。
假设 dp[x][y] 表示前 x 件物品,在不超过重量 y 的时候的最大价值。枚举一下第 x 件物品的情况:

  • 情况一:如果选第 x 件物品,则前 x - 1 件物品得到的重量不能超过 y - w[x]。
  • 情况二:如果不选 x 件物品,则前 x - 1 件物品得到的重量不能超过 y。

无论哪种情况,我们都需要去求解 x - 1 件物品的情况。

所以,dp[x][y] 可能等于 dp[x-1][y],也就是不取第 x 件物品的时候,价值和之前的一样。
也可能是 dp[x-1][y - w[x]] + v[x],也就是决定拿第 x 件物品的情况,当然会加上 x 物品的价值。
两种可能性中,应该选择价值最大的那个,状态转移方程如下:
dp[x][y] = Max{dp[x-1][y], dp[x-1][y-w[x]]+v[x]}

对于 dp 矩阵来说,行数是物品的数量 n,列数是背包的最大承重 w。然后再从左到右,从上到下计算所有的 dp 的值即可。

该矩阵中的每个值的求解都代表一个更小的背包问题。
初始情况一:对于第0列,它的含义是背包的容量为0。此时物品的价值呢?没有。因此,第一列都填入0。
初始情况二:对于第0行,它的含义是屋内没有物品。那么没有任何物品的背包里的价值多少呢?还是没有!所有都是0。
所以我们可以把这个矩阵的大小定义为 dp[n+1][y+1],从第二行第二列也就是 dp[1][1] 的位置开始带入状态转移方程进行计算,其实这也解决了我长期以来对这个矩阵的行列都+1的困扰

代码

public class Solution {
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @param V: Given n items with value V[i]
     * @return: The maximum value
     */
    public int backPackII(int m, int[] A, int[] V) {
        // 1.定义状态矩阵,dp[i][j]表示在0..i个物品中不超过j重的情况下的背包的最大价值
        int[][] dp = new int[A.length + 1][m + 1];
        // 2.状态转移方程:dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-A[i-1]] + V[i-1])
        for (int i = 1; i <= A.length; i++) {
            for (int j = 1; j <= m; j++) {
                dp[i][j] = dp[i-1][j];
                if (j >= A[i-1]) {
                    dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-A[i-1]] + V[i-1]);
                }
            }
        }
        return dp[A.length][m];
    }
}

关注我的微信公众号(曲健磊的个人随笔),观看更多精彩内容:
0-1 背包问题 - 求装入背包中的所有物品的最大价值_第1张图片

你可能感兴趣的:(【算法相关】)