基础算法--背包问题

本文详细介绍了背包问题的两个变体——完全背包和0-1背包,包括它们的概念、特点以及相应的解决策略,如贪心算法和动态规划。通过实例演示了如何使用这两种方法求解背包问题以实现价值最大化。
摘要由CSDN通过智能技术生成

概念

背包问题是一个经典的组合优化问题,其目标是在给定的一组物品中选择一些物品放入背包中,使得物品的总价值最大化,同时要求背包的总重量不超过背包的容量限制。

背包问题有两种常见的变体:完全背包和0-1背包。

鉴于完全背包计算过程相对0-1背包简单,这里先讲完全背包。

完全背包(无限背包)

在完全背包问题中,每个物品可以选择放入背包中的次数是无限的,即可以重复选择。每个物品有一个固定的重量和价值,背包有一个固定的容量限制。目标是选择一些物品放入背包中,使得物品的总价值最大化,同时背包的总重量不能超过容量限制。

完全背包问题可以使用贪心算法来解决。具体的算法思路是按照物品的单位重量价值从大到小进行排序,然后依次选择单位重量价值最大的物品放入背包中,直到背包的总重量达到容量限制或者所有物品都被选择完。

假设有一个背包的容量限制为10,现在有以下物品可供选择:

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

接下来我们用使用贪心算法解决这个问题。

1、定义背包容量capacity、物品的重量数组weights和物品的价值数组values。
2、创建一个一维数组dp,长度为capacity + 1,用于保存背包容量从0到capacity时的最大价值。
3、初始化dp[0]为0,表示背包容量为0时的最大价值为0。
4、对于每个背包容量i,从1到capacity,进行循环计算最大价值:

  • 对于每个物品j,从0到n-1,进行循环:
    • 如果物品的重量weights[j]小于等于当前背包容量i,则可以考虑放入该物品:
      • 更新dp[i]为dp[i - weights[j]] + values[j]和dp[i]的较大值,表示选择放入物品j后的最大价值。

5、循环结束后,dp[capacity]即为背包容量为capacity时的最大价值。
6、返回dp[capacity]作为结果。

代码示例:

public class KnapsackProblem {

    public static int knapsack(int capacity, int[] weights, int[] values) {
        int n = weights.length;
        int[] dp = new int[capacity + 1];

        for (int i = 0; i <= capacity; i++) { // 遍历背包容量
            for (int j = 0; j < n; j++) { // 遍历物品数组
                if (weights[j] <= i) { // 如果物品的重量小于等于当前背包容量
                    dp[i] = Math.max(dp[i], dp[i - weights[j]] + values[j]); // 更新背包容量为i时的最大价值
                }
            }
        }

        return dp[capacity]; // 返回背包容量为capacity时的最大价值
    }

    public static void main(String[] args) {
        int capacity = 10;
        int[] weights = {3, 4, 5};
        int[] values = {8, 10, 15};

        int maxValue = knapsack(capacity, weights, values);
        System.out.println("Maximum value: " + maxValue);
    }
}

输出结果:

Maximum value: 30

0-1背包

在0-1背包问题中,每个物品要么完整地放入背包中,要么不放入,不能进行切割(即每个背包最多只能被选一次)。每个物品有一个固定的重量和价值,背包有一个固定的容量限制。目标是选择一些物品放入背包中,使得物品的总价值最大化,同时背包的总重量不能超过容量限制。

可以使用动态规划来解决0-1背包问题。具体的算法思路是创建一个二维数组dp,其中dp[i][j]表示在前i个物品中,背包容量为j时的最大价值。然后使用递推关系式计算dp数组的值,最终dp[n][W]就是问题的解,其中n为物品的数量,W为背包的容量。

同样假设有一个背包的容量限制为10,现在有以下物品可供选择:

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

我们的目标是选择一些物品放入背包中,使得物品的总价值最大化,同时背包的总重量不能超过10。

对于这个问题,我们可以使用动态规划来解决。

1、创建一个二维数组dp,大小为(物品数量+1)×(背包容量+1)。dp[i][j]表示在前i个物品中,背包容量为j时的最大价值。

2、初始化第一行和第一列为0,表示没有物品或者背包容量为0时,最大价值都为0。

3、使用递推关系式计算dp数组的值。对于每个物品i,考虑两种情况:

  • 如果物品i的重量大于当前背包容量j,则无法放入背包中,此时dp[i][j]等于dp[i-1][j],即前i-1个物品在背包容量为j时的最大价值。

  • 如果物品i的重量小于等于当前背包容量j,则可以选择放入背包中或者不放入。我们选择其中的最大值作为dp[i][j]的值:

    • 如果选择放入物品i,则总价值为dp[i][j-w[i]] + v[i],其中w[i]为物品i的重量,v[i]为物品i的价值。(这里理解起来有点难)
    • 如果选择不放入物品i,则总价值为dp[i-1][j],即前i-1个物品在背包容量为j时的最大价值。

4、最终,dp[n][W]就是问题的解,其中n为物品的数量,W为背包的容量。

代码示例:

public class KnapsackProblem {

    public static int knapsack(int capacity, int[] weights, int[] values) {
        int n = weights.length;
        int[][] dp = new int[n + 1][capacity + 1];

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= capacity; j++) {
                if (weights[i - 1] > j) {
                    // 当前物品的重量大于背包容量,无法放入背包
                    dp[i][j] = dp[i - 1][j];
                } else {
                    // 可以选择放入或不放入当前物品,取最大值
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);
                }
            }
        }

        return dp[n][capacity];
    }

    public static void main(String[] args) {
        int capacity = 10;
        int[] weights = {3, 4, 5};
        int[] values = {8, 10, 15};

        int maxValue = knapsack(capacity, weights, values);
        System.out.println("Maximum value: " + maxValue);
    }
}

输出结果:

Maximum value: 25
  • 48
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值