Loading

0-1背包问题

题目

给你一个可装载重量为W的背包和N个物品,每个物品有重量和价值两个属性。其中第i个物品的重量为wt[i],价值为val[i],现在让你用这个背包装物品,最多能装的价值是多少?

举个简单的例子,输入如下:

N = 3, W = 4
wt = [2, 1, 3]
val = [4, 2, 3]

算法返回 6,选择前两件物品装进背包,总重量 3 小于W,可以获得最大价值 6。

题目就是这么简单,一个典型的动态规划问题。这个题目中的物品不可以分割,要么装进包里,要么不装,不能说切成两块装一半。这也许就是 0-1 背包这个名词的来历。

思路

  • 利用二维dp数组,计算最大价值,当物品为一个时候,能怎么装,然后当物品为两个时候,又能怎么装才能使价值最大...以此类推,直到达到列出所有的物品和背包的最大容量时,dp[n][m]就是我们要求的最大能获得的价值
  • 如果一个物品的重量大于当前背包的最大承重,那么就直接不装
  • 如果物品小于最大承重,再进行择优:比较转和不装哪个价值大,那么就选它

代码实现

public static int knapsack(int w, int n, int[] wt, int[] val) {
    // 定义dp数组,dp的每一个元素代表背包不同容量和不同物品重量对应得最大的价值
    int[][] dp = new int[n + 1][w + 1];

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= w; j++) {
            // 如果当前单个物品的重量超过了当前背包的最大重量,则装不下,就不装了(wt[i-1]: 索引从1开始)
            if (j < wt[i - 1]) {
                // 不装
                dp[i][j] = dp[i - 1][j];
            } else {
                // 装入或则不装入背包,择优
                // dp[i-1][j - wt[i-1]]:将当前的背包重量减去当前要装入的物品的重量,然后去查找剩下的重量的对应的最大的值(尽量让背包装满)
                // dp[i-1][j] 即不装入背包
                dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - wt[i - 1]] + val[i - 1]);
            }
        }
    }
    return dp[n][w];
}

复杂度分析

  • 时间复杂度为O(nw)
  • 空间复杂度为O(nw)
posted @ 2020-11-01 14:59  linzeliang  阅读(124)  评论(0)    收藏  举报