青训营X豆包MarsCode 技术训练营第一课 | 豆包MarsCode AI 刷题

121 阅读3分钟

解析:动态规划解决背包问题

在编程和算法领域中,背包问题(Knapsack Problem)是一个经典的优化问题。它描述的是给定一组物品,每种物品都有自己的重量(或体积)和价值,在限定的总重量(或总体积)内,如何选择物品使得总价值最大。本文将通过一个具体的 Java 实现来解析如何使用动态规划(Dynamic Programming, DP)解决背包问题。

问题定义

假设我们有 n 种物品,每种物品有一个重量 weights[i] 和一个价值 values[i]。给定一个背包,其最大容量为 m,我们的目标是选择一些物品装入背包,使得在不超过背包容量的前提下,背包内物品的总价值最大。

动态规划思路

动态规划是一种通过将复杂问题分解为更小的子问题来解决的方法。对于背包问题,我们可以定义一个二维数组 dp,其中 dp[i][j] 表示前 i 种物品在容量为 j 的背包中所能得到的最大价值。

  1. 初始化dp 数组的大小为 (n+1) x (m+1),初始值全为 0。dp[0][j] 表示没有物品可选时,无论背包容量多大,最大价值都为 0。dp[i][0] 表示背包容量为 0 时,无论有多少种物品可选,最大价值也都为 0。

  2. 状态转移:对于每种物品 i 和每个容量 j,有两种选择:

    • 不选物品 i:则 dp[i][j] = dp[i-1][j],即当前物品的价值为 0。
    • 选物品 i:如果 j >= weights[i-1],则 dp[i][j] = max(dp[i][j], dp[i-1][j-weights[i-1]] + values[i-1]),即加上当前物品的价值。
  3. 最终结果dp[n][m] 就是我们所求的最大价值。

代码实现

以下是上述思路的 Java 实现:

java复制代码
	public class Main {

	 

	    public static int solution(int n, int[] weights, int[] values, int m) {

	        // 定义 dp 数组

	        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

	    }

	}

代码解析

  • solution 方法:接受物品数量 n、重量数组 weights、价值数组 values 和背包容量 m 作为输入,返回一个整数表示最大价值。
  • dp 数组:用于存储中间结果,dp[i][j] 表示前 i 种物品在容量为 j 的背包中的最大价值。
  • 双重循环:外层循环遍历每种物品,内层循环遍历每个可能的背包容量。
  • 状态转移:根据是否选择当前物品来更新 dp 数组的值。
  • main 方法:包含几个测试用例,用于验证算法的正确性。

结论

通过上述实现,我们可以看到动态规划在解决背包问题时的强大能力。通过合理地定义状态转移方程,我们可以高效地计算出最优解。这种方法不仅适用于 0/1 背包问题,还可以扩展到其他类型的背包问题,如完全背包问题和多重背包问题。希望这篇文章能帮助你更好地理解背包问题及其动态规划解法。