动态规划-01背包问题

news2024/9/21 16:45:20

01背包问题简介

01背包问题是一种经典的动态规划问题。问题描述为:给定一组物品,每种物品都有自己的重量和价值,在限定的总重量内,如何选择物品装入背包,使得背包中的物品总价值最大。每种物品只能选择装入或不装入背包一次(即0或1次),这就是“01”的含义。

问题参数

  • 物品数量 (n):背包中可供选择的物品总数。
  • 物品重量 (weights[i]):第i个物品的重量。
  • 物品价值 (values[i]):第i个物品的价值。
  • 背包容量 (W):背包能够承载的最大重量。

目标

  • 最大化背包中物品的总价值,同时确保所有物品的总重量不超过背包的容量。

动态规划解法

对于这个问题,我们可以使用动态规划(DP)的方法来解决。我们可以定义一个二维数组dp[i][j],其中dp[i][j]表示在前i个物品中,当背包容量为j时,能够装入背包的最大价值。状态转移方程为:

dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i])

其中,w[i]是第i个物品的重量,v[i]是第i个物品的价值。如果第i个物品的重量大于背包的剩余容量j,那么该物品不能装入背包,此时dp[i][j]就等于dp[i-1][j](即不装入第i个物品时的最大价值)。否则,我们可以选择装入第i个物品或者不装入,取这两种情况下的较大值。

int knapsack01(int W, vector<int>& weights, vector<int>& values, int n) {  
    vector<vector<int>> dp(n + 1, vector<int>(V + 1, 0));
    //dp[i][j]:前i个的物品,所装的物品体积不超过j时,能够装下的最大价值

    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= V; j++) {
            dp[i][j] = dp[i - 1][j];
            if (j - vw[i - 1][0] >= 0) {
                dp[i][j] = max(dp[i - 1][j - vw[i - 1][0]] + vw[i - 1][1], dp[i][j]);
            }
        }
    }
    return dp[n][V];
}  

然而,在实际应用中,我们可以将二维数组优化为一维数组,以节省空间。

我们定义一个数组dp,其中dp[j]表示在容量为j的背包中能够装入的最大价值。

状态转移方程

对于每个物品i和每个容量j,我们有以下选择:

  • 不装入第i个物品:此时背包的价值就是前i-1个物品在容量为j的背包中的最大价值,即dp[j] = dp[j](实际上这一步在循环中通常不会显式执行,因为dp[j]在更新前已经保存了前一个状态的值)。
  • 装入第i个物品:如果第i个物品的重量小于或等于当前考虑的容量j,我们可以选择将其装入背包,此时背包的价值就是前i-1个物品在容量为j-weights[i]的背包中的最大价值加上第i个物品的价值,即dp[j] = dp[j-weights[i]] + values[i]

我们需要在两种选择中取较大值来更新dp[j]

初始化
  • dp[0]应该初始化为0,表示容量为0的背包无法装入任何物品,因此价值为0。
  • 其余dp[j]j > 0)可以初始化为一个非常小的数(如负无穷),但在实际编程中,由于我们总是从较小的容量向较大的容量更新dp数组,且每次更新都是取较大值,因此通常不需要显式初始化(除了dp[0])。
遍历顺序
  • 物品遍历:通常从第一个物品遍历到最后一个物品。
  • 容量遍历:对于每个物品,我们需要从背包的最大容量W向下遍历到该物品的重量(包括)。这是为了确保在计算dp[j]时,dp[j-weights[i]]已经包含了不考虑当前物品时的最优解。
int knapsack01(int W, vector<int>& weights, vector<int>& values, int n) {  
    vector<int> dp(W + 1, 0);  
    for (int i = 0; i < n; ++i) {  
        for (int j = W; j >= weights[i]; --j) {  
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i]);  
        }  
    }  
    return dp[W];  
}  

关于01背包问题,还有另一个问题:若背包恰好装满,求至多能装多大价值的物品

 当背包需要恰好装满,并且我们要求在这个条件下至多能装多大价值的物品时,我们可以使用与01背包问题相同的动态规划解法,但在输出结果时需要注意一个关键点:我们需要检查在背包容量W时是否达到了一个非零的价值,因为这表明我们可以恰好装满背包。

在01背包问题的标准解法中,我们使用一个一维数组dp,其中dp[j]表示容量为j的背包所能装载的最大价值。对于每个物品,我们遍历所有可能的背包容量(从大到小),并更新dp数组以考虑是否将该物品加入背包。

当背包需要恰好装满时,我们需要特别关注dp[W]的值。如果dp[W]是非零的,那么这意味着存在一个选择方案,可以使得背包恰好装满,并且其价值等于dp[W]。如果dp[W]仍然是初始值(在大多数情况下是0,但也可能取决于你的初始化方式),那么这表明不存在一个方案可以恰好装满背包。

实现步骤

  1. 初始化:将dp[0]设置为0(空背包的价值为0),其他dp[j](对于j > 0)可以设置为一个非常小的数(尽管在01背包问题中,由于我们总是取最大值,所以它们通常不会被访问到,除非你试图在背包未装满时得到部分解)。然而,在这个特定问题中,你只需要关心dp[W],所以除了dp[0]之外的其他元素的具体值并不重要。

  2. 动态规划过程:对于每个物品,从背包容量W开始向下遍历到该物品的重量。对于每个容量j,检查是否应该将该物品加入背包(即,如果j >= weights[i],则比较dp[j]dp[j-weights[i]] + values[i])。

  3. 结果检查:在动态规划过程完成后,检查dp[W]的值。如果dp[W]是非零的,那么它就是在背包恰好装满的情况下可以装载的最大价值。如果dp[W]是零,那么不存在一个方案可以恰好装满背包。

int knapsack01ExactFull(int W, vector<int>& weights, vector<int>& values, int n) {  
    vector<int> dp(W + 1, 0);  
    for (int i = 0; i < n; ++i) {  
        for (int j = W; j >= weights[i]; --j) {  
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i]);  
        }  
    }  
    // 如果dp[W]非零,表示可以恰好装满背包  
    if (dp[W] > 0) {  
        return dp[W];  
    } else {  
        // 如果需要,可以在这里处理无法恰好装满背包的情况  
        return -1; // 或者其他适当的错误代码/值  
    }  
}  

 

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

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

相关文章

影刀RPA实战:网页爬虫之药品数据

1 实战目标 这次给大家带来的实战示例是采集中国医药信息平台上的药品数据&#xff0c;主要获取药品名称&#xff0c;介绍&#xff0c;药品类型&#xff0c;处方类型&#xff0c;医保类型&#xff0c;参考价格&#xff0c;药品成分&#xff0c;性状&#xff0c;适应病症&#…

Qt断点调试

Qt断点操作与调试窗口介绍_哔哩哔哩_bilibili 下图来自上面的视频&#xff01;&#xff01;&#xff01; 1.断点调试常用的快捷键 ShiftF11&#xff1a;单步退出所在的那个函数&#xff0c;进行下一步 2.查看函数的调用情况 3.监视变量的值&#xff08;当前断点时的变量值&am…

《操作系统 - 清华大学》第 0 章:操作系统概述 —— 内容概述

介绍一下有关操作系统的一个基本的一个概述&#xff1a; 比如说什么是操作系统&#xff1f;为什么要学习操作系统&#xff0c;以及如何学好操作系统&#xff1f;然后接下来会介绍一下&#xff0c;当前操作系统一些实例以及操作系统的历史&#xff0c;它的演变的一个过程。最后…

wsl2桥接网络 ubuntu到弃坑到又跳坑

搜索Hyper-V image.png 如下图进入虚拟交换机管理器 image.png image.png C:\Users\Administrator下存放 ; 这是 WSL 2 的配置文件 [wsl2] processors4 ; 设置 WSL 2 可以使用的最大 CPU 核心数为 4&#xff0c;自行修改 memory4GB …

使用 KMeans 聚类算法 对鸢尾花数据集进行无监督学习的简单示例

代码功能 主要功能&#xff1a; 加载数据集&#xff1a; 代码使用 load_iris() 函数加载了鸢尾花数据集&#xff08;Iris dataset&#xff09;。这个数据集包含 150 条样本&#xff0c;每条样本有 4 个特征&#xff0c;对应于 3 种不同的鸢尾花。 KMeans 聚类&#xff1a; 使用…

Flowable基础篇

Flowable基础篇 课程环境说明&#xff1a; JDK8Flowable6.7.2MySQL8 一、基础知识科普 1.工作流发展 BPM(BusinessProcessManagement)&#xff0c;业务流程管理是一种管理原则&#xff0c;通常也可以代指BPMS(BusinessProcessManagementSuite)&#xff0c;是一个实现整合不同…

JAVA毕业设计178—基于Java+Springboot+vue的智能家具管理系统(源代码+数据库+万字论文)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootvue的智能家具管理系统(源代码数据库万字论文)178 一、系统介绍 本项目前后端分离(可以改为ssm版本)&#xff0c;分为用户、管理员两种角色 1、用户&#xff1…

从HarmonyOS升级到HarmonyOS NEXT-环信SDK数据迁移

2024年6月21日 HarmonyOS NEXT &#xff08;后续称之为 NEXT&#xff09; 正式发布&#xff0c;随着 NEXT 稳定版的逐渐临近&#xff0c;各个应用及SDK正在忙于适配 NEXT 系统&#xff0c;同样也面临着系统升级时如何对数据的迁移适配。本文通过使用环信 SDK 介绍如何从 Harmon…

计算机毕业设计推荐-基于python大数据的个性化图书数据可视化分析

&#x1f496;&#x1f525;作者主页&#xff1a;毕设木哥 精彩专栏推荐订阅&#xff1a;在 下方专栏&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; 实战项目 文章目录 实战项目 一、个性化图书数据可视化分析-项…

带你0到1之QT编程:十四、QV/HBoxLayout和QStatckedWidget双剑合璧

此为QT编程的第十四谈&#xff01;关注我&#xff0c;带你快速学习QT编程的学习路线&#xff01; 每一篇的技术点都是很很重要&#xff01;很重要&#xff01;很重要&#xff01;但不冗余&#xff01; 我们通常采取总-分-总和生活化的讲解方式来阐述一个知识点&#xff01; …

【我的 PWN 学习手札】tcache extend

目录 前言 一、利用手法 二、流程演示 &#xff08;1&#xff09;三块物理相邻的堆块 &#xff08;2&#xff09;溢出修改 size &#xff08;3&#xff09;释放该 chunk &#xff08;4&#xff09;重新申请该 chunk &#xff08;5&#xff09;释放第三块 chunk&#x…

算法-Init

&#xff08;1&#xff09;有限性&#xff08;Finiteness&#xff09;&#xff1a;算法必 需在有限步骤内结束&#xff1b; &#xff08;2&#xff09;确定性&#xff08;Definiteness&#xff09;&#xff1a;算法的每一个步骤必须清晰无歧义地定义&#xff1b; &#xff08;3…

科研入门学习

学习视频链接 为什么要读论文 读哪些论文 论文的分类 论文质量 如何找论文 根据领域大牛的名字进行搜索查看高水平论文引用的论文&#xff0c;高水平论文引用的论文很大程度也是高水平的论文 如何整理论文 如何读论文 读论文的困境 不同人群阅读差异 读论文的方式 论文的结构…

叉车限速器外接LED屏,监督厂区安全,让速度慢下来!

叉车限速器外接LED屏&#xff0c;可实时显示当前叉车行驶中的速度&#xff0c;单/双面电子显示屏供用户选择&#xff0c;方便企业人员监控司机当前行驶速度&#xff0c;当速度超过指定值时&#xff0c;叉车速度报警系统发出声光警示&#xff0c;提醒行人、司机&#xff0c;超速…

【ArcGIS微课1000例】0121:面状数据共享边的修改方法

文章目录 一、共享边概述二、快速的修改办法1. 整形共享边2. 修改边3. 概化边缘一、共享边概述 面状数据共享边指的是两个或多个面状数据(如多边形)共同拥有的边界。在地理信息系统(GIS)、三维建模、大数据分析等领域,面状数据共享边是描述面状空间数据拓扑关系的重要组成…

C / C++的内存管理

前言 Hello&#xff0c;我又回来了&#xff0c;今天我们将继续学习C部分&#xff0c;今天我们将承接前面的知识&#xff0c;继续学习C的内存管理&#xff0c;今天的内容较为重要&#xff0c;所以我们废话不多说&#xff0c;我们还是按例三连上车&#xff0c;开始我们今天内容&…

【图灵完备 Turing Complete】游戏经验攻略分享 Part.4 处理器架构

比较有难度的一个部分。 运算单元ALU&#xff0c;其实就是通过OP选择计算方式&#xff0c;然后选通某个计算&#xff0c;之后输出。每个计算逐个实现就行了。 下面是一个优化占地面积的ALU&#xff0c;变得紧凑了一点。 下面是一个简单的OP选通原理线路。判断是立即数寻址&…

吹爆吊打 GPT-4 的大模型新王者Reflection 70B,是否言过其实?

引言 一觉睡西天&#xff0c;谁知梦里乾坤大。只身眠净土&#xff0c;只道其中日月长。 小伙伴们好&#xff0c;我是微信公众号《小窗幽记机器学习》的小编&#xff1a;卖铁观音的小男孩。今天这篇小作文主要介绍这几天网上狂吹的开源新晋王者Reflection 70B&#xff0c;该模型…

【医疗大数据】医疗保健领域的大数据管理:采用挑战和影响

选自期刊**《International Journal of Information Management》**&#xff08;IF:21.0) 医疗保健领域的大数据管理&#xff1a;采用挑战和影响 1、研究背景 本研究的目标是调查阻止医疗机构实施成功大数据系统的组织障碍&#xff0c;识别和评估这些障碍&#xff0c;并为管理…

Qemu开发ARM篇-1、环境搭建篇

文章目录 1、目标2、欢迎来到qemu世界3、开发环境4、依赖安装5、编译安装qemu 1、目标 我们的目标是在x86平台上搭建上arm开发环境&#xff0c;及在x86平台模拟一台arm设备&#xff0c;以达到能快速在x86平台上学习arm相关知识&#xff0c;如uboot启动、kernel开发调试等&…