青训营—0,1背包最大价值问题

78 阅读2分钟

题目描述

一个旅行者外出旅行时需要将 n 件物品装入背包,背包的总容量为 m。每个物品都有一个重量和一个价值。你需要根据这些物品的重量和价值,决定如何选择物品放入背包,使得在不超过总容量的情况下,背包中物品的总价值最大。

给定两个整数数组 weights 和 values,其中 weights[i] 表示第 i 个物品的重量,values[i] 表示第 i 个物品的价值。你需要输出在满足背包总容量为 m 的情况下,背包中物品的最大总价值。

测试样例

样例1

输入:n = 3 ,weights = [2, 1, 3] ,values = [4, 2, 3] ,m = 3
输出:6

样例2

输入:n = 4 ,weights = [1, 2, 3, 2] ,values = [10, 20, 30, 40] ,m = 5
输出:70

样例3

输入:n = 2 ,weights = [1, 4] ,values = [5, 10] ,m = 4
输出:10

思路

可以使用动态规划来解决这个问题。定义一个二维数组 dp,其中 dp[i][j] 表示前 i 件物品放入容量为 j 的背包中所能获得的最大价值。 状态转移方程:

  • 如果不选择第 i 件物品:dp[i][j] = dp[i - 1][j]
  • 如果选择第 i 件物品(前提是当前容量 j 大于等于该物品的重量 weights[i-1]):dp[i][j] = max(dp[i][j], dp[i - 1][j - weights[i - 1]] + values[i - 1])

Java代码

public class Main {
    public static int solution(int n, int[] weights, int[] values, int m) {
        // write code here
        int[][] dp = new int[n + 1][m + 1];

        // 遍历每个物品
        for (int i = 1; i <= n; i++) {
            int weight = weights[i - 1];
            int value = values[i - 1];
            // 遍历每个容量
            for (int j = 0; j <= m; j++) {
                // 如果不选当前物品
                dp[i][j] = dp[i - 1][j];
                // 如果选择当前物品
                if (j >= weight) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - weight] + value);
                }
            }
        }

        return dp[n][m];
    }

    public static void main(String[] args) {
        System.out.println(solution(3, new int[]{2, 1, 3}, new int[]{4, 2, 3}, 3) == 6);
        System.out.println(solution(4, new int[]{1, 2, 3, 2}, new int[]{10, 20, 30, 40}, 5) == 70);
        System.out.println(solution(2, new int[]{1, 4}, new int[]{5, 10}, 4) == 10);
    }
}

复杂度分析

时间复杂度:O(n * m),其中 n 是物品的数量,m 是背包的容量。需要遍历每个物品和每个可能的背包容量。

空间复杂度:O(n * m),使用了一个二维数组 dp 来存储每个状态的最大价值。