数据结构学习Day01背包

背包

泛型(参数化类型)

集合类的抽象数据类型的一个关键特性是我们应该可以用它们存储任意类型的数据。

class name即代表了一种参数类型。是一种象征性的占位符,表示用例将会使用某种具体的数据类型。

自动装箱拆箱

类型参数必须被实例化为引用类型,因此java有一种特殊机制来使用泛型代码能够处理原始数据类型。

封装类型
Boolean Byte Character Double Float Integer Long Short
原始数据类型的引用类型
boolean byte char double float int long short

举个例子:

Stack<Integer> stack = new Stack<Integer>();
stack.push(17);   	//自动装箱(int -> Integer)
int i = stack.pop(); 	//自动拆箱 (Integer -> int)

背包

背包是一种不支持从中删除元素的集合数据类型____目的在于帮助用例收集元素并迭代遍历所有收集到的元素。

下面让我们通过一个具体的例子来说明背包算法的应用。

假设我们有一个容量为10的背包,然后有以下物品可供选择:

物品1:重量4,价值8
物品2:重量3,价值5
物品3:重量2,价值3

我们的目标是选择哪些物品放入背包,使得总价值最大化。

首先,我们创建一个二维数组dp,其大小为(4, 11),其中行数表示物品的数量,列数表示背包的容量加1(为了包括背包容量为0的情况)。

接下来,我们按照动态规划算法的步骤逐步填充dp数组:

  1. 初始化边界条件:dp[0][j] = 0(没有物品可选时,背包的价值为0),dp[i][0] = 0(背包容量为0时,无法放入任何物品)。

  2. 对于物品1(重量4,价值8):

    • 如果物品1的重量4大于当前背包容量j(j从0到10),则dp[1][j] = dp[0][j](当前物品放不进背包,最大价值等于前一个物品的最大价值)。
    • 如果物品1的重量4小于等于当前背包容量j:
      • 放入物品1:dp[1][j] = max(dp[0][j-4] + 8, dp[0][j])(放入物品1后,最大价值为前一个物品在容量为j-4的背包中的最大价值加上物品1的价值,与前一个物品的最大价值进行比较,取较大值)。
      • 不放入物品1:dp[1][j] = dp[0][j](不放入物品1,最大价值等于前一个物品的最大价值)。
  3. 对于物品2(重量3,价值5):

    • 如果物品2的重量3大于当前背包容量j,则dp[2][j] = dp[1][j]。
    • 如果物品2的重量3小于等于当前背包容量j:
      • 放入物品2:dp[2][j] = max(dp[1][j-3] + 5, dp[1][j])。
      • 不放入物品2:dp[2][j] = dp[1][j]。
  4. 对于物品3(重量2,价值3):

    • 如果物品3的重量2大于当前背包容量j,则dp[3][j] = dp[2][j]。
    • 如果物品3的重量2小于等于当前背包容量j:
      • 放入物品3:dp[3][j] = max(dp[2][j-2] + 3, dp[2][j])。
      • 不放入物品

3:dp[3][j] = dp[2][j]。

最终,我们得到的dp数组如下所示:

  0   1   2   3   4   5   6   7   8   9   10

物品1 0 0 0 0 8 8 8 8 8 8 8
物品2 0 0 0 5 8 8 8 13 13 13 13
物品3 0 0 3 5 8 8 11 13 13 14 16

最后一个元素dp[3][10]的值为16,表示在给定的物品中选择一些放入容量为10的背包中的最大总价值为16。

从dp数组的填充过程可以看出,选择放入物品2和物品3可以达到最大价值16。因此,我们选择物品2和物品3放入背包,总重量为5,总价值为8。

这就是背包算法的一个例子,通过动态规划的方法,我们找到了在给定条件下最佳的物品组合,使得它们的总价值最大化。

代码

以下是用Java编写的0/1背包问题的核心算法:

public class Knapsack {
    public static int knapsack(int[] values, int[] weights, int capacity) {
        int n = values.length;
        int[][] dp = new int[n + 1][capacity + 1];
        
        for (int i = 1; i <= n; i++) {
            int value = values[i - 1];
            int weight = weights[i - 1];
            
            for (int j = 1; j <= capacity; j++) {
                if (weight > j) {
                    dp[i][j] = dp[i - 1][j];
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight] + value);
                }
            }
        }
        
        return dp[n][capacity];
    }
    
    public static void main(String[] args) {
        int[] values = {8, 5, 3};
        int[] weights = {4, 3, 2};
        int capacity = 10;
        
        int maxValue = knapsack(values, weights, capacity);
        System.out.println("最大价值:" + maxValue);
    }
}

在这个例子中,我们定义了一个knapsack方法,接收物品的价值数组values、重量数组weights和背包容量capacity作为参数。它返回背包中物品的最大总价值。

knapsack方法中,我们使用一个二维数组dp来记录在选择前几个物品时,放入背包的情况下的最大总价值。通过两个嵌套的循环遍历物品和背包容量,根据动态规划的思想逐步填充dp数组。

最后,我们在main方法中定义了一个示例,使用提供的物品价值和重量数组以及背包容量调用knapsack方法,并打印出结果。

运行上述代码,输出将会是:

最大价值:16

这证明了在给定的条件下,我们选择了最佳的物品组合,使得它们的总价值最大化。

你可能感兴趣的:(数据结构,学习,动态规划)