当前位置: 首页 > news >正文

动态规划 背包问题

动态规划 背包问题

问题描述:
有一个背包,总容量为12。有6件物品,每件物品的重量和价值不同,求在背包总容量12的前提下,装进物品的最大价值以及装进物品的编号

单个物品重量和价值:

在这里插入图片描述

为方便进行思考,我们将物品按照重量价值递增,重新排序

在这里插入图片描述


针对此问题,我们可以先列一张表格,标识当前背包容量为j时,前i个物品的最大价值。

在这里插入图片描述

例如X(3,3),代表当背包容量为3时,前3个物品可装入的最大价值。


第一行X(0,0)X(0,12),代表当背包容量为0到12时,前0个物品可装入的最大价值,前0个物品不存在没有价值,即价值恒为0,因此第一行都填入0。

同理第一列X(0,0)X(6,0),代表当背包容量为0时,第0个物品到第6个物品可装入的最大价值,因为背包容量为0,没有物品可以装下,所以第一列都填入0。

在这里插入图片描述


X(1,1) 代表当背包容量为1时,前1个物品的最大价值。由于W(1)=1,刚好可以装入,那么X(i,j)=X(1,1)=V(1)=4 ,因此填入4。并且不论之后背包容量如何扩展,前1个物品的最大价值恒为4。

在这里插入图片描述


当开始第三行,即X(2,j) 填写时,就需要判断背包容量够不够装下当前物品,如果能装下,那装下当前物品和不装当前物品哪个价值最大:

  1. 背包装不下

    当背包容量j小于当前第i个物品重量W(i) 时,即j<W(i) 判断为装不下,此时的最大价值X(i,j) 与前一个X(i-1,j) 的最大价值一样,即X(i,j)=X(i-1,j)

  2. 背包装得下

    当背包容量j大于等于当前第i个物品重量W(i) 时,判断要不要装进背包。

    2.1:装入当前物品时的最大价值Value1
    背包总容量j减去当前物品的重量W(i) 后,获取剩余总容量的上一物品最大价值X(i-1,j-W(i)) 与当前物品的价值V(i) 相加,即 Value1=X(i-1,j-W(i)) + V(i)

    2.2:不装当前物品时的最大价值Value2
    前一个物品i-1在此背包总容量j情景下的最大价值X(i-1,j),即 Value2=X(i-1,j)

Value1-Value2 大于0则取当前和值Value1,反之取上一物品此背包总容量情景下的最大价值Value2

此时不理解上述公式没关系,跟着下面的填数去慢慢理解


X(2,1) 填数,首先判断背包能否装下:

j=1W(2)=2j<W(2),因此当背包容量为1时,物品2装不下,此时最大价值取前一个物品i-1此背包总容量j情景下的最大价值X(i-1,j)=X(2-1,1)=X(1,1)=4,因此X(2,1)=4

在这里插入图片描述


X(2,2) 填数,首先判断背包能否装下:

j=2W(2)=2j=W(2),因此当背包容量为2时,物品2装得下

此时需要判断要不要装物品2:

装入当前物品时的最大价值:Value1 = X(i-1,j-W(i)) + V(i) = X(2-1,2-2) + 1 = X(1,0) + 1 = 0 + 1 = 1

不装当前物品时的最大价值:Value2 = X(i-1,j) = X(2-1,2) = X(1,2) = 4

Value1<Value2,因此取上一物品此背包总容量情景下的最大价值,即X(2,2) = X(1,2) = 4

在这里插入图片描述


X(2,3) 填数,首先判断背包能否装下:

j=3W(2)=2j>W(2),因此当背包容量为3时,物品2装得下

此时需要判断要不要装物品2:

装入当前物品时的最大价值:Value1 = X(i-1,j-W(i)) + V(i) = X(2-1,3-2) + 1 = X(1,1) + 1 = 4 + 1 = 5

不装当前物品时的最大价值:Value2 = X(i-1,j) = X(2-1,3) = X(1,3) = 4

Value1>Value2,因此取当前物品的价值加剩余总容量的最佳价值,即X(2,3) = 5

在这里插入图片描述


按照此规律,我们将表全部填充完毕:

在这里插入图片描述

取两个坐标进行验证:


例如1:X(4,3) 填数,首先判断背包能否装下:

j=3W(4)=3j=W(4),因此当背包容量为3时,物品4装得下

此时需要判断要不要装物品4:

装入当前物品时的最大价值:Value1 = X(i-1,j-W(i)) + V(i) = X(4-1,3-3) + 6 = X(3,0) + 6 = 0 + 6 = 6

不装当前物品时的最大价值:Value2 = X(i-1,j) = X(4-1,3) = X(3,3) = 7

Value1<Value2,因此取上一物品此背包总容量情景下的最大价值,即X(4,3) = X(3,3) = 7


例如2:X(4,4) 填数,首先判断背包能否装下:

j=4W(4)=3j>W(4),因此当背包容量为4时,物品4装得下

此时需要判断要不要装物品4:

装入当前物品时的最大价值:Value1 = X(i-1,j-W(i)) + V(i) = X(4-1,4-3) + 6 = X(3,1) + 6 = 4 + 6 = 10

不装当前物品时的最大价值:Value2 = X(i-1,j) = X(4-1,4) = X(3,4) = 7

Value1>Value2,因此取当前物品的价值加剩余总容量的最佳价值,即X(4,3) = 10


代码实现

int bag = 12; // 背包总容量
int number = 6; // 物品数量
int[] weight = {1, 2, 2, 3, 4, 6}; // 物品重量数组
int[] value = {4, 1, 3, 6, 8, 2}; // 物品价值数组
int[][] max = new int[number + 1][bag + 1]; // 最大价值数组int value1 = 0; // 过渡值:装入当前物品时的最大价值
int value2 = 0; // 过渡值:不装当前物品时的最大价值// 找出最大价值for (int i = 1; i <= number; i++) { // 行for (int j = 1; j <= bag; j++) { // 列// 判断背包能否装得下if (j < weight[i - 1]) { // 装不下max[i][j] = max[i - 1][j]; // 与前一个物品的最大价值相同} else { // 能装下// 前一个物品剩余重量的最大价值+当前物品的价值value1 = max[i - 1][j - weight[i - 1]] + value[i - 1];// 前一个物品当前重量的最大价值value2 = max[i - 1][j];// 取最大值max[i][j] = value1 > value2 ? value1 : value2;}}
}System.out.println(Arrays.deepToString(max)); // 打印最大价值数组
System.out.println("MaxValue = " + max[number][bag]); // 打印最大价值

结果输出:

[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
[0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4], 
[0, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], 
[0, 4, 4, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8], 
[0, 4, 4, 7, 10, 10, 13, 13, 14, 14, 14, 14, 14], 
[0, 4, 4, 7, 10, 12, 13, 15, 18, 18, 21, 21, 22], 
[0, 4, 4, 7, 10, 12, 13, 15, 18, 18, 21, 21, 22]]
MaxValue = 22

在上述结果基础上,如果需要知道最大价值情况下,都装入了哪些商品,就需要进行回溯。

在这里插入图片描述

已知X[6][12] 为最大价值,首先判断它有没有装入背包,即X[6][12] = X[6-1][12] 是否生效,若相等,则未装入,继续以X[6-1][12] 作为最大价值进行判断。

X[5][12] 同理与X[5-1][12] 比较,发现不相等,通过公式22 = X[5-1][j-W(5)] + V[5] = X[4][12-4] + 8 = X[4][8] + 8 ,即X[4][8] = 22-8 = 14,反算后值也相等,则第5个物品装入了背包。

以此类推,公式为:

  1. 未装入背包
    X[i][j] = X[i-1][j],则当前物品未装入背包。

  2. 转入背包
    X[i-1][j-W(i)] = X[i][j] - V[i],则当前物品装入背包。


代码实现:


List list = new ArrayList<>(); // 装入物品编号// 回溯查找装入物品编号
findNo(number, bag);
Collections.sort(list); // 按照物品编号排序
System.out.println(list.toString());void findNo(int i, int j) {if (i > 0) {// 判断是否装入背包if (max[i][j] == max[i - 1][j]) {// 与上一物品最大价值相等,当前物品未装入findNo(i - 1, j);} else if (j - weight[i-1] >= 0 && (max[i - 1][j - weight[i-1]] == max[i][j] - value[i-1])) {  // 与上一物品最大价值不相等且反算成功,当前物品装入,继续递归list.add(i);findNo(i - 1, j - weight[i-1]);}}
}

结果输出:

[1, 2, 3, 4, 5]

相关文章:

动态规划 背包问题

动态规划 背包问题 问题描述&#xff1a; 有一个背包&#xff0c;总容量为12。有6件物品&#xff0c;每件物品的重量和价值不同&#xff0c;求在背包总容量12的前提下&#xff0c;装进物品的最大价值以及装进物品的编号 单个物品重量和价值&#xff1a; 为方便进行思考&#…...

C++ Primer Plus 学习笔记(四)—— 内存模型和名称空间

1 单独编译 C允许将组件函数放在独立的文件即头文件中&#xff0c;头文件中可以包含以下内容&#xff1a; 函数原型&#xff1b;使用#define或const定义的符号常量&#xff1b;结构声明&#xff1b;类声明&#xff1b;模板声明&#xff1b;内联函数。 注意&#xff0c;在包含…...

详解基于 Celestia、Eclipse 构建的首个Layer3 链 Nautilus Chain

以流支付为主要概念的Zebec生态&#xff0c;正在推动流支付这种新兴的支付方式向更远的方向发展&#xff0c;该生态最初以Zebec Protocol的形态发展&#xff0c;并从初期的Solana进一步拓展至BNB Chian以及Near上。与此同时&#xff0c;Zebec生态也在积极的寻求从协议形态向公链…...

列表与数组的转化

目录用np.array(a)将列表转换为数组列表转数组的特殊情况(一)列表转数组的特殊情况(二)针对子元素个数不一致的解决办法用a.tolist()函数将数组转化为列表在python的学习中&#xff0c;经常会用到数组与列表的相互转化&#xff0c;本文主要介绍下关于数组与列表转化的问题。用n…...

docker 运行花生壳实现内外网穿透

环境&#xff1a;centos 7 ,64位 1、创建一个指定的文件夹作为安装示例所用&#xff0c;该示例文件夹为“hsk-nwct”。“hsk-nwct”内创建“app”文件夹作为docker容器挂载出来的文件。 2、在“app”内下载花生壳linux安装包&#xff0c;下载花生壳应用&#xff1a;花生壳客户…...

操作系统——16.时间片轮转、优先级、多级反馈队列算法

这篇文章我们来看一下进程调度算法中的时间片轮转、优先级、多级反馈队列算法 目录 1.概述 2.时间片轮转调度算法&#xff08;RR&#xff0c;Round-Robin&#xff09; 3.优先级调度算法 4.多级反馈队列调度算法 5.分析对比 1.概述 首先&#xff0c;我们来看一下这篇文章…...

Python3.8.8-Django3.2-Redis-连接池-数据类型-字符串-list-hashmap-命令行操作

文章目录1.认识Redis1.1.优点1.2.缺点2.在Django中Redis的连接3.Redis的基础用法3.1.hashmap结构3.2.list结构4.命令行查看数据库5.作者答疑1.认识Redis Remote DIctionary Server(Redis) 是一个key-value 存储系统&#xff0c;是跨平台的非关系型数据库。是一个开源的使用 AN…...

Android kotlin 系列讲解(进阶篇)高级项目架构模式 - MVVM

<<返回总目录 1、MVVM是什么 MVVM是Model-View-ViewModel的缩写&#xff0c;是一种高级项目架构模式。 MVVM架构可以将程序结构主要分成三个部分&#xff1a; Model&#xff1a;数据模型部分&#xff0c;包括从服务端获取的json数据或者从本地获取的数据等等View&…...

8. 查找

1 题目描述 查找成绩10开启时间2021年09月24日 星期五 18:00折扣0.8折扣时间2021年11月15日 星期一 00:00允许迟交否关闭时间2021年11月23日 星期二 00:00 输入 n(n ≤ 10^6)个不超过 10^9的单调不减的&#xff08;就是后面的数字不小于前面的数字&#xff09;非负整数 &#…...

二分查找算法

感谢“五点七边”工作室的算法讲解&#xff0c;详细内容可以参考视频讲解 二分查找为什么总是写错&#xff1f;_哔哩哔哩_bilibili 此处仅是个人学习总结 以target等于5为例&#xff0c;输入: 1 2 3 5 5 5 8 9 1. 找到第一个 > target 的元素 判断条件 < target&am…...

Git(3)之远程服务器

Git基础之远程服务器 Author&#xff1a;onceday date&#xff1a;2023年3月5日 满满长路有人对你微笑过嘛… windows安装可参考文章&#xff1a;git简易配置_onceday_CSDN博客 參考文档&#xff1a; 《progit2.pdf》&#xff0c;Progit2 Github。《git-book.pdf》 文章目…...

Javalin解构

Javalin Javalin是一个轻量级http框架&#xff0c;我们可以很容易的了解请求的处理过程及其设计&#xff0c;具有较高的学习意义。 从demo说起 public static void main(String[] args) {Javalin app Javalin.create(config -> {System.out.println("用户配置"…...

yolov5算法,训练模型,模型检测

嘟嘟嘟嘟&#xff01;工作需要&#xff0c;所以学习了下yolov5算法。是干什么的呢&#xff1f; 通俗来说&#xff0c;可以将它看做是一个小孩儿&#xff0c;通过成年人&#xff08;开发人员&#xff09;提供的大量图片的学习&#xff0c;让自己知道我看到的哪些场景需要提醒给成…...

linux系统防火墙开放端口

linux系统防火墙开放端口 在外部访问CentOS中部署应用时&#xff0c;需要通过防火墙管理软件,开端口,或者直接关闭防火墙进行解决(不建议) 加粗样式 常用命令&#xff1a; systemctl start firewalld #启动 systemctl stop firewalld #停止 systemctl status firewalld #查看…...

CSAPP第九章 虚拟内存

理解虚拟内存的原因 本章前部分描述虚拟内存是如何工作的&#xff0c;后一部分描述应用程序如何使用和管理虚拟内存 物理和虚拟寻址 虚拟内存作为缓存的工具 页表 页命中 缺页 虚拟内存作为内存管理的工具 简化链接&#xff0c;简化加载&#xff0c;简化共享&#xff0c;简化…...

numpy数组与矩阵运算(二)

文章目录矩阵生成与常用操作矩阵生成矩阵转置查看矩阵特性矩阵乘法计算相关系数矩阵计算方差、协方差、标准差计算特征值与特征向量计算逆矩阵求解线性方程组奇异值分解函数向量化矩阵生成与常用操作 矩阵生成 扩展库numpy中提供的matrix()函数可以用来把列表、元组、range对…...

Dubbo 中 Zookeeper 注册中心原理分析

Dubbo 中 Zookeeper 注册中心原理分析 文章目录Dubbo 中 Zookeeper 注册中心原理分析一、ZooKeeper注册中心1.1 ZooKeeper数据结构1.2 ZooKeeper的Watcher机制1.3 ZooKeeper会话机制1.4 使用ZooKeeper作为注册中心二、源码分析2.1 AbstractRegistry2.2 FailbackRegistry2.2.1 核…...

素数产生新的算法(由筛法减法改为增加法)--哥德巴赫猜想的第一次实际应用

素数产生新的算法&#xff08;由筛法减法改为增加法&#xff09;--哥德巴赫猜想的第一次实际应用 摘要&#xff1a;长期以来&#xff0c;人们认为哥德巴赫猜想没有什么实际应用的。 现在&#xff0c;我假设这个不是猜想&#xff0c;而是定理或公理&#xff0c;就产生了新的应用…...

递归-需要满足三个条件

一&#xff0c;概述 递归是一种应用非常广泛的算法&#xff08;或者编程技巧&#xff09;。很多数据结构和算法的编码实现都要用到递归&#xff0c;比如 DFS 深度优先搜索、前中后序二叉树遍历等。 去的过程叫“递”&#xff0c;回来的过程叫“归”。基本上所有的递归问题都可…...

【剑指Offer-Java】两个栈实现队列

题目 用两个栈实现一个队列。队列的声明如下&#xff0c;请实现它的两个函数 appendTail 和 deleteHead &#xff0c;分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素&#xff0c;deleteHead 操作返回 -1 ) 输入&#xff1a; [“CQueue”,“appendT…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)

题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

第八部分:阶段项目 6:构建 React 前端应用

现在&#xff0c;是时候将你学到的 React 基础知识付诸实践&#xff0c;构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段&#xff0c;你可以先使用模拟数据&#xff0c;或者如果你的后端 API&#xff08;阶段项目 5&#xff09;已经搭建好&#xff0c;可以直接连…...