Java之动态规划的背包问题

news2024/11/15 9:53:16

目录

动态规划问题

一:01背包问题

1.问题描述

2.分析问题

3.代码实现(二维数组)

4.滚动数组实现(一维数组)

二:完全背包问题

1.题目描述

2.问题分析

3.代码实现


动态规划问题

动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为小问题,进行解决,从而一步步获取最优解的处理算法

动态规划对于解决最优子结构啊和重叠子问题等问题时候,有着很好的应用

对于动态规划问题,大致可以分为以下几步:

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

一:01背包问题

1.问题描述

有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

例如以下问题:

有一个背包,它的容量为4磅,现有以下物体

物品重量价格
物品011500
物品143000
物品232000

1)要求达到的目标为装入的背包的总价值最大,并且重量不超出                                                    2)要求装入的物品不能重复

2.分析问题

对于解决这样的动态规划的背包问题,还是采用通用的五个步骤

1.确定dp数组(dp table)以及下标的含义

对于01背包问题,可以采用二维数组或者一维数组,这里为了便于理解,先采用一维数组

定义一个二维数组dp[i][j],这里dp数组的含义为:将物品(0到i)放入到背包容量为j的背包里面,价值总和最大为dp[i][j]

2.确定递推公式

对于放入物品i,有两种状态:将物品i放入到背包中,不将物品i放入到背包中

不放物品i:不放物品i,相当于将物品0到i-1放入到背包容量为j的背包中,这个时候递推公式dp[i][j]就可以等于dp[i-1][j]

放物品i:当放入物品i的时候,此时首先需要判断的是否物品i可以放入到背包容量为j的背包中,要是使背包可以放入物品i,则背包的容量至少剩余weight[i],即放入物品0到i-1的时候,背包剩余的容量至少为j-weight[i],因此放入0到i-1物品的最大价值为dp[i-1][j-weight[i]],放入物品i时候的最大价值就为dp[i-1][j-weight[i]]+value[i]

此时dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i])

3.dp数组如何初始化

由递推公式dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i])可以看出,第i行需要由上一行推算出,所以第i=0行的数据一定要进行初始化,具体如下

        for (int i = weight[0]; i <= bagSize; ++i) {
            dp[0][i] = value[0];
        }

4.确定遍历顺序

实现先遍历背包还是先遍历物品,其实都可以,但是先遍历物品更好理解

确定递推的方向:

dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]); 递归公式中可以看出dp[i][j]是靠dp[i-1][j]和dp[i - 1][j - weight[i]]推导出来的,dp[i][j]是由其左上角的元素推出来的,因此需要自上到下,自左到右的遍历顺序

5.举例推导dp数组

对dp数组进行填表的操作

01234
001500150015001500
101500150015003000
201500150020003500

3.代码实现(二维数组)

    public static int maxValue(int[] weight, int[] value, int bagSize) {
        int num = weight.length;
        int[][] dp = new int[num][bagSize + 1];//0-i物品任取到容量为j的背包的最大价值
        for (int i = weight[0]; i <= bagSize; ++i) {
            dp[0][i] = value[0];
        }
        for (int i = 1; i < num; ++i) {
            for (int j = 1; j <= bagSize; ++j) {
                if (j < weight[i]) {//如果当前物品的重量大于背包的容量
                    dp[i][j] = dp[i - 1][j];//不取当前的物品
                } else {
                    //dp[i - 1][j]不取当前的物品的价值,
                    //dp[i - 1][j - weight[i]] + value[i]取当前物品
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
                }

            }
        }
        return dp[num - 1][bagSize];

    }

4.滚动数组实现(一维数组)

在使用二维数组的时候,递推公式:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

下一行的元素仅有上一行的元素推出来,因此可以使用滚动数组,也就是一维dp数组

1.确定dp数组(dp table)以及下标的含义

dp[j]表示背包容量为j的商品最大价值为dp[j]

2.确定递推公式

和二维dp数组一样,也是有两种选择,一种放入物品i,一种不放物品i,因此可以写成

此时dp[j]=max(dp[j],dp[j-weight[i]]+value[i])

3.dp数组如何初始化

根据递推公式可以看出dp[j]由此层推出,此时我们可以将dp初始化为0

4.确定遍历顺序

上面我们已经写过了二维dp数组,我们知道本层是由下上方的元素推出来的,现在我们采用的是一维dp数组,如果我们还是采用从左到右进行递推的话,后面的元素就可能因为前边元素的变化而变化,不是由上一层的元素推出来的了,相当于二维dp数组我们根据本层前边的元素推出本层后边的元素,这样就不符合我们想要表达的意思了,如何我们采用的是从右到左的遍历顺序的话,这样彼此之间就不会因为后边元素的改变而影响前边元素的改变了,相当于上一层的元素推出本层的元素

这里是与二维dp数组最大的不同,需要自己理解清楚

5.举例推导dp数组

三次for循环的数据如下

第一次
01500150015001500
第二次
01500150015003000
第三次
01500150020003500

 代码实现

    public static int maxValue(int[] weight, int[] value, int bagSize) {
        int[] dp = new int[bagSize + 1];//0-i物品任取到容量为j的背包的最大价值

        for (int i = 0; i < weight.length; ++i) {//物品的数量
            for (int j = bagSize; j >= weight[i]; --j) {//背包剩余的重量
                dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
            }
            System.out.println(Arrays.toString(dp));

        }
        return dp[bagSize];

    }

二:完全背包问题

1.题目描述

有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。

例如如下问题:

有一个背包,它的容量为4磅,现有以下物体

物品重量价格
物品011500
物品143000
物品232000

完全背包问题与01背包问题基本相似,唯一的区别就是多重背包问题的物品数量是无限的

2.问题分析

01背包的滚动数组的遍历顺序是从右到左的,可以保证每个物品只被遍历一次,而完全背包问题每个物品可以被添加多次,因此需要进行从左到右进行遍历,可以确保每个物品有被多次添加的可能

举例推导dp数组

第一次
01500300045006000
第二次
01500300045006000
第三次
01500300045006000

3.代码实现

    public static int perfectPackage(int[] weight, int[] value, int bagWeight) {
        int[] dp = new int[bagWeight + 1];
        for (int i = 0; i < weight.length; ++i) {
            for (int j = weight[i]; j <= bagWeight; ++j) {
                dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
            }
        }
        return dp[bagWeight];

    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/197360.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

若依代码生成器-Domain代码生成篇(一)

若依代码生成器的前一段代码的阅读&#xff0c;我们了解了若依代码生成器的一些逻辑&#xff0c;包括通过数据库的information_schema. TABLES查询表信息&#xff0c;以及information_schema. COLUMNS查询指定表的列信息&#xff0c;将其转换到表gen_table与gen_table_column中…

SETR项目运行记录

项目简要介绍 全称为Swin-Transformer-Semantic-Segmentation&#xff0c;看名字我们就知道使用的是transformer&#xff0c;做的是语义分割方面&#xff0c;使用的数据集是Cityscapes。在本文中我们并不对其原理进行解读&#xff0c;只是调试运行该项目。 项目下载地址&#…

2023年深圳CPDA数据分析师认证将于2/25正式开班,快来报名

CPDA数据分析师认证是中国大数据领域有一定权威度的中高端人才认证&#xff0c;它不仅是中国较早大数据专业技术人才认证、更是中国大数据时代先行者&#xff0c;具有广泛的社会认知度和权威性。 无论是地方政府引进人才、公务员报考、各大企业选聘人才&#xff0c;还是招投标加…

C++这么难,为什么我们还要学习C++?

文章目录前言1. 为什么难学2. C的意义3. 什么时候该用C4. 如何学习C5. 学前勉言前言 C 可算是一种声名在外的编程语言了。这个名声有好有坏&#xff0c;从好的方面讲&#xff0c;C 性能非常好&#xff0c;哪个编程语言性能好的话&#xff0c;总忍不住要跟 C 来单挑一下&#x…

[架构之路-98]:《软件架构设计:程序员向架构师转型必备》-8-确定关键性需求与决定系统架构的因素

第8章 确定关键性需求是什么决定了软件系统的架构&#xff1f;&#xff01;没有大的争议的是&#xff1a;需求决定了软件系统的架构&#xff01;那么什么样的需求对软件系统的架构影响最大&#xff1f;8.1 众说纷纭——什么决定了架构8.1.1 用例驱动论&#xff1a;功能性需求用…

算法训练营 day30 回溯算法 组合总和 组合总和II 分割回文串

算法训练营 day30 回溯算法 组合总和 组合总和II 分割回文串 组合总和 39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组…

简易三子棋游戏实现

哈喽小伙伴们大家好&#xff0c;我们一起学习三子棋游戏的创建吧。在开始之前我们先来复习一下&#xff0c;函数声明放在头文件中函数定义放在源文件中。那么什么是函数声明和函数定义呢&#xff1f;所谓函数声明就是说明函数的返回参数&#xff0c;函数类型&#xff0c;函数名…

基于PHP的图书管理系统

摘要网络技术给生活带来了十分的便利。所以把图书管理与现在网络相结合。在图书馆发展的整个过程中&#xff0c;图书担负着最重要的角色。为满足如今日益复杂的管理需求&#xff0c;各类管理系统程序也在不断改进。本课题所设计的图书管理系统&#xff0c;使用B/S架构&#xff…

C++之this指针

this指针到底是什么&#xff1f;this 实际上是成员函数的一个形参&#xff0c;在调用成员函数时将对象的地址作为实参传递给 this。不过 this 这个形参是隐式的&#xff0c;它并不出现在代码中&#xff0c;而是在编译阶段由编译器默默地将它添加到参数列表中。我们操作一个对象…

Hadoop配置手册1:hadoop环境搭建与测试

Hadoop配置手册1 Date: September 25, 2022 第1章 hadoop环境搭建 1.1 安装Vmware软件 下载地址&#xff1a;https://www.onlinedown.net/soft/45831.htm 运行安装程序&#xff0c;并连续点击下一步安装 输入密钥&#xff0c;启动程序 详细参考&#xff1a;https://blog.csd…

2023年19个数学建模竞赛重磅来袭!!!

更新时间&#xff1a;2022年2月3日 本人的团队全是计算机的研究生&#xff0c;从本科到研究生有丰富的打比赛和数模的经验&#xff0c;有需要指导的&#xff0c;请私信我 相关链接 &#xff08;1&#xff09;【数学建模】2022年整年所有数学建模竞赛时间表 &#xff08;2&a…

再过半小时,你就能理解Kafka的基本原理了

kafka总结一.定义二.基础架构及术语三.工作流程分析3.1发送数据3.2保存数据3.2.1 partition结构3.2.2 message结构3.2.3 存储策略3.2.4 消费数据一.定义 Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;可以处理消费者规模的网站中的所有动作流数据&#xff0c;具有…

基于 PyTorch 的目标检测(YOLO实现)

目标检测是一个直到最近才开始逐渐被征服的挑战。解决这个问题对于自动化和自动驾驶来说是至关重要的。对解决办法的追求导致了各种方法的发展。我想要描述一些主要的方法&#xff0c;在过去的21目标检测已经被使用&#xff0c;然后讨论 Yolov3的实现。讨论方法引言虽然深度学习…

windows 7 离线安装vs20219,GraalVM 打包java成可执行程序

环境准备 由于vs2022不支持windows 7 &#xff0c;故用vs2019版。 如果是 win7 系统&#xff0c;在安装下载的依赖项前需要安装 win7 所需要的两个补丁 KB4490628和KB4474419 &#xff0c;下载地址分别为&#xff08;下载后直接安装即可&#xff09;&#xff1a; 参考这篇博客…

vite --- 搭建开发环境

目录 下载安装和初始化VSCode 安装Node.js yarn 使用 pnpm 安装与使用 搭建第一个Vite项目 使用 PNPM创建项目 项目目录解读 下载安装和初始化VSCode 1、访问网站 Visual Studio Code - Code Editing. Redefined 2、选择平台版本 选择符合自己操作系统的安装包下载完毕…

接口测试及接口抓包常用的测试工具有哪些?

目录 接口 接口测试的重要性 常用抓包工具 01、F12 02、Fiddler抓包工具 03、Charles抓包工具 04、Firebug抓包工具 05、httpwatch抓包工具 06、Wireshark抓包工具 07、SmartSniff抓包工具 常用接口测试工具 01、Postman 02、Jmeter 03、RESTClient 04、WireMock…

655. 汽车大甩卖2 etiger.vip 答案

题目描述 有n辆车大甩卖&#xff0c;第i辆车售价a[i]元。有m个人带着现金来申请购买&#xff0c;第i个到现场的人带的现金为b[i]元&#xff0c;只能买价格不超过其现金额的车子。你是大卖场总经理&#xff0c;希望将车和买家尽量多地进行一对一配对&#xff0c;请问最多卖出多…

Qt 开发环境搭建

一、Qt下载与安装 1、qt下载网站https://download.qt.io/ 其中各个目录含义如下&#xff1a; 目录说明snapshots/预览版&#xff0c;最新开发测试的Qt库和开发工具online/在线安装源official_releases/正式发布版&#xff0c;是与开发版相对应的稳定版Qt库和开发工具&#x…

利用哨兵简化实现难度

首先先回顾一下链表的插入和删除&#xff0c;如果需要在一个结点p后边插入一个结点&#xff0c;那么只需要下边两行代码&#xff1a; new_node->next p->next; p->next new_node;但是当往链表插入第一个结点时候&#xff0c;上边的代码就不能用了。需要进行下边的处…

【vue2】vue框架学习前置必备基础知识

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;数组 | 字符串中常用方法、对象解构语法、function |箭头函数this指向、展开运算符、原型…