动态规划——01背包问题(Java)

3.2 动态规划算法

介绍
在这里插入图片描述

动态规划算法经典问题—背包问题
在这里插入图片描述
在这里插入图片描述
思路

  • 该问题是01背包问题

  • 声明定义w[i],v[i],v[i][j]

    • w[i] : 第i个物品的重量
    • v[i] : 第i个物品的价值
    • v[i][j]:前i种(个)物品存放在容量为j的背包内的最大价值**(i=0 没有物品 i=1只能放置吉他 i=2可以放吉他、音响 i=3可以放吉他、音响、电脑)**
  • 为什么背包最大容量C已经给定,代表背包容量的J还要设置为可变的呢?
    ​ 因为我们是在进行动态规划,v[i][j]代表容量为J的背包存放i个物品可以获取的最大价值,是在背包容量为j时的最优解。当J增长时,在计算新的局部最优解是需要考虑J更小时的其他局部最优解。比如在J=4时,我们需要考虑J=2、J=1时的局部最优解,从而计算得到J=4时的全部最优解

  • 每一次添加新物品到容量为 J 的背包中,需要进行以下流程判断

    • W[i] > J , 添加新物品的重量大于当前背包的最大容量,直接不用考虑将该物品添加到背包,最大价值使用之前的

      v[i][j] = v[i-1][j]

    • W[i] <= J , 添加新物品重量小于当前背包的最大容量,在 不加入当前物品时的最大价值当前物品价值+扣去当前物品重量后剩余背包空间可以存放物品的最大价值 之间选取最大值,然后作为v[i][j]的新方案

  • 使用一张图来方便理解
    在这里插入图片描述

代码

import java.util.Arrays;

public class knapsack {
    public static void main(String[] args) {
        int[] w = {1, 4, 3};//物品的重量
        int[] val = {1500, 3000, 2000};//物品的价值
        int m = 4;//背包的容量
        int n = val.length;//物品的个数

        //为了记录放入商品的情况,我们定义一个二维数组
        int[][] isPut = new int[n + 1][m + 1];
        //创建二维数组
        //v[i][j]:表示在前i个(种)物品中能够装入容量为j的背包中的最大价值
        int[][] v = new int[n + 1][m + 1];
        //初始化第一行和第一列【可有可无】
        for (int i = 0; i < v.length; i++) {//v.length:获取二维数组的行数
            v[i][0] = 0;//将第一列设置为0
        }
        //将第一行设置为0
        Arrays.fill(v[0], 0);
        // 因为前面初始化过第一行和第一列的数值固定为0,所以以下i和j下标从1开始
        for (int i = 1; i < v.length; i++) {
            for (int j = 1; j < v[0].length; j++) {
                // w[i] 需要从0开始
                if (w[i-1] > j) { // 添加物品重量大于背包容量大小
                    v[i][j] = v[i - 1][j];
                } else {
                    // 若将物品加入到背包内最大价值最大,将物品加入到背包内
                    if (v[i - 1][j] < (val[i - 1] + v[i - 1][j - w[i - 1]])) {
                        v[i][j] = val[i - 1] + v[i - 1][j - w[i - 1]];
                        // 若将新物品加入到背包内 在标记数组内标记
                        isPut[i][j] = 1;
                    } else { // 选择不将新物品加入到背包内
                        v[i][j] = v[i - 1][j];
                    }
                }
            }
        }
        //输出最后我们是放入的那些商品
        int i = isPut.length - 1;
        int j = isPut[0].length - 1;
        System.out.println("最大价值: "+v[i][j]);
        System.out.println("添加物品情况: ");
        // 从最后一个物品开始,判断在J容量下有没有加入对应物品
        //      1.没有加入就判断前一个物品在J容量下有没有加入背包。
        //      2.加入了,就判断剩余背包容量下J-W[i]下前一个物品有没有加入
        //      3.直到全部物品都检查过一遍后才停止
        while (i > 0 && j > 0) {//从加入的最后一个物品开始倒序查找
            if (isPut[i][j] == 1) {
                System.out.printf("第%d个商品放入背包\n", i);
                j -= w[i - 1];
            }
            i--;
        }
    }
}

输出结果

最大价值: 3500
添加物品情况:3个商品放入背包
第1个商品放入背包

参考博客

详解:动态规划算法【Java实现】——背包问题_动态规划背包问题时间效率_嗨森-程序杀手的博客-CSDN博客

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值