DP:二维费用背包问题
文章目录
- 🎵二维费用背包问题
- 🎶引言
- 🎶问题定义
- 🎶动态规划思想
- 🎶状态定义和状态转移方程
- 🎶初始条件和边界情况
- 🎵例题
- 🎶1.一和零
- 🎶2.盈利计划
- 🎵总结


🎵二维费用背包问题
🎶引言
背包问题是算法中的经典问题之一,其变种繁多。本文将介绍二维费用背包问题及其解决方案。
🎶问题定义
二维费用背包问题可以描述为:给定 (N) 个物品,每个物品有两个费用和一个价值,在两种费用的限制下,如何选择物品使得总价值最大。
🎶动态规划思想
动态规划是解决背包问题的常用方法。通过定义合适的状态和状态转移方程,我们可以有效地解决二维费用背包问题。
🎶状态定义和状态转移方程
我们定义 dp[i][j][k] 表示前 i 个物品在费用1不超过 j 和费用2不超过 k 的情况下的最大价值。状态转移方程为:
d p [ i ] [ j ] [ k ] = max ( d p [ i − 1 ] [ j ] [ k ] , d p [ i − 1 ] [ j − c o s t 1 [ i ] ] [ k − c o s t 2 [ i ] ] + v a l u e [ i ] ) dp[i][j][k] = \max(dp[i-1][j][k], dp[i-1][j-cost1[i]][k-cost2[i]] + value[i]) dp[i][j][k]=max(dp[i−1][j][k],dp[i−1][j−cost1[i]][k−cost2[i]]+value[i])
🎶初始条件和边界情况
初始条件为 dp[0][j][k] = 0,表示没有物品时的最大价值为 0。边界条件需要根据实际问题进行处理。
🎵例题
🎶1.一和零
题目:
样例输出和输入:
算法原理:
这道题就是让我们找子集的长度,这个子集满足:当中的0不大于m个,当中的1不大于n个,最后返回最大的子集的长度,所以我们首先想到的是二维费用背包问题,因为有两个限制,这里的背包的限制就是0和1的个数的限制,这里的物品其实就是每个字符串。
状态表示: d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示从前 i i i个物品中选择的所有组合中,满足0的个数不大于m,1的个数不大于n个的所有组合中子集长度最大的那个的长度。
状态转移方程:

这里的a和b代表的是当前i位置字符串中0和1分别的个数,所以我们在进行填表的时候应该遍历一下字符串,将当中的0和1分别记录一下,状态转移方程:
d p [ i ] [ j ] [ k ] = m a x ( d p [ i − 1 ] [ j ] [ k ] , d p [ i − 1 ] [ j − a ] [ k − b ] ) dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-a][k-b]) dp[i][j][k]=max(dp[i−1][j][k],dp[i−1][j−a][k−b])
初始化:
代码:
未优化的代码:
class Solution {
public:int findMaxForm(vector<string>& strs, int m, int n){int sz = strs.size();vector<vector<vector<int>>> dp(sz + 1, vector<vector<int>>(m + 1, vector<int>(n + 1)));for (int i = 1;i <= sz;i++){//统计一下字符串中0和1的个数int a = 0, b = 0;for (auto e : strs[i - 1]){if (e == '1')b++;else a++;}for (int j = 0;j <= m;j++){for (int k = 0;k <= n;k++){dp[i][j][k] = dp[i - 1][j][k];if (j >= a && k >= b)dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - a][k - b] + 1);}}}return dp[sz][m][n];}
};
滚动数组优化的代码:
class Solution {
public:int findMaxForm(vector<string>& strs, int m, int n){int sz = strs.size();vector<vector<int>> dp(m + 1, vector<int>(n + 1));for (int i = 1;i <= sz;i++){//统计一下字符串中0和1的个数int a = 0, b = 0;for (auto e : strs[i - 1]){if (e == '1')b++;else a++;}for (int j = m;j >=a;j--)for (int k = n;k >=b;k--)dp[j][k] = max(dp[j][k], dp[j - a][k - b] + 1);}return dp[m][n];}
};
运行结果:

🎶2.盈利计划
题目:
样例输出和输入:
算法原理:
这道题每个group对应一个profit,下标是对应的。

根据上面的图片加上题目要求,我们可以得知,我们每次选择的利润必须大于给定的 m i n P r o f i t minProfit minProfit然后每次需要的人口不能超过 n n n,最后求出满足这个条件的所有组合有多少种。
状态表示: d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示从前i个工作计划中选择,人数不超过i的,但是盈利大于k的所有组合数的总和。
状态转移方程:
第一种状态:不选择i位置, d p [ i − 1 ] [ j ] [ k ] dp[i-1][j][k] dp[i−1][j][k]
第二种状态:选择i位置,首先考虑二维 d p [ i − 1 ] [ j − g r o u p [ i ] ] dp[i-1][j-group[i]] dp[i−1][j−group[i]]这里我们考虑一下 j − g r o u p [ i ] ≤ 0 j-group[i]\leq0 j−group[i]≤0是否成立将group[i]移到右边去可以得到: j ≤ g r o u p [ i ] j\leq group[i] j≤group[i]这个是什么意思呢?表示i工作需要的人口是大于总人口j的,所以这肯定是不可能的,所以这里中只能是 j − g r o u p [ i ] ≥ 0 j-group[i]\geq0 j−group[i]≥0,我们再来考虑三维的: d p [ i − 1 ] [ j − g r o u p [ i ] ] [ k − p r o f i t [ i ] ] dp[i-1][j-group[i]][k-profit[i]] dp[i−1][j−group[i]][k−profit[i]]我们来考虑 k − p r o f i t [ i ] ≤ 0 k-profit[i]\leq0 k−profit[i]≤0是否成立,首先我们还是继续移一下项: k ≤ p r o f i t [ i ] k \leq profit[i] k≤profit[i]这里k表示总的利润,profit表示当前工作产出的利润,所以这里的意思就表示无论前面总利润是多少,这里都都能满足当前的利润,所以我们只需要选择0即可,所以第二种状态:
d p [ i − 1 ] [ j − g r o u p [ i ] ] [ m a x ( 0 , k − p r o f i t [ i ] ) ] dp[i-1][j-group[i]][max(0,k-profit[i])] dp[i−1][j−group[i]][max(0,k−profit[i])]
最后这两种状态的总和就是当前状态的所有组合的总和:
d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j ] [ k ] + d p [ i − 1 ] [ j − g r o u p [ i ] ] [ m a x ( 0 , k − p r o f i t [ i ] ) ] dp[i][j][k]=dp[i-1][j][k]+dp[i-1][j-group[i]][max(0,k-profit[i])] dp[i][j][k]=dp[i−1][j][k]+dp[i−1][j−group[i]][max(0,k−profit[i])]
代码:
未优化的代码:
class Solution {
public:int profitableSchemes(int n, int minProfit, vector<int>& group, vector<int>& profit) {int len = group.size();int MOD = 1e9 + 7;vector<vector<vector<int>>> dp(len + 1, vector<vector<int>>(n + 1, vector<int>(minProfit + 1)));for (int j = 0;j <= n;j++){dp[0][j][0] = 1;}for (int i = 1;i <= len;i++){for (int j = 0;j <= n;j++){for (int k = 0;k <= minProfit;k++){dp[i][j][k] = dp[i - 1][j][k];if (j >= group[i-1])dp[i][j][k] += dp[i - 1][j - group[i - 1]][max(0, k - profit[i - 1])];dp[i][j][k] %= MOD;}}}return dp[len][n][minProfit];}
};
优化过后的代码:
int profitableSchemes(int n, int minProfit, vector<int>& group, vector<int>& profit)
{int len = group.size();int MOD = 1e9 + 7;vector<vector<int>> dp(n + 1, vector<int>(minProfit + 1));for (int j = 0;j <= n;j++)dp[j][0] = 1;for (int i = 1;i <= len;i++)for (int j = n;j >= group[i - 1];j--)for (int k = 0;k <= minProfit;k++){dp[j][k] += dp[j - group[i - 1]][max(0, k - profit[i - 1])];dp[j][k] %= MOD;}return dp[n][minProfit];
}
运行结果:

🎵总结
通过本文的学习,我们了解了二维费用背包问题的基本概念和解决方法。与传统的单一费用背包问题不同,二维费用背包问题在解决时需要同时考虑两种费用的限制,这使得问题更具挑战性,但也更贴近实际应用场景。我们通过动态规划的方法,逐步构建状态转移方程,并利用二维数组来存储中间结果,从而实现了对问题的高效求解。
在实际应用中,掌握二维费用背包问题的解决思路,可以帮助我们在资源分配、投资组合等多方面优化决策。希望通过本次的学习,大家不仅能够掌握相关的算法技巧,还能够举一反三,灵活应用于更多复杂的优化问题中。
今后,我们将继续探讨更为复杂的动态规划问题,进一步提升算法设计和问题求解能力。谢谢大家的阅读,希望本文对你有所帮助。
相关文章:
DP:二维费用背包问题
文章目录 🎵二维费用背包问题🎶引言🎶问题定义🎶动态规划思想🎶状态定义和状态转移方程🎶初始条件和边界情况 🎵例题🎶1.一和零🎶2.盈利计划 🎵总结 …...
C语言标准库中的函数
由于C语言标准库中的函数非常多,我将按类别列出一些常见函数及其作用。请注意,这里不可能列出所有函数,但我会尽量覆盖主要的类别和函数。 ### 标准输入输出 - printf: 格式化输出到标准输出(通常是屏幕)。 - scanf: …...
Qt5.9.9 关于界面拖动导致QModbusRTU(QModbusTCP没有测试过)离线的问题
问题锁定 参考网友的思路: Qt5.9 Modbus request timeout 0x5异常解决 网友认为是Qt的bug, 我也认同;网友认为可以更新模块, 我也认同, 我也编译了Qt5.15.0的code并成功安装到Qt5.9.9中进行使用,界面拖…...
API的定义理解
前言 在程序员的日常工作中,“API”这个词在程序员的口中重复的次数,绝对是名列前茅的。 但是对刚开始工作的新人来说,API这个概念还是比较模糊。 确实,API这个概念是随着语义环境而不一样的,所以会让人迷惑。 下面…...
启航IT之旅:高考假期预习指南
标题:启航IT之旅:高考假期预习指南 随着高考的落幕,许多有志于IT领域的学子们即将踏上新的学习旅程。这个假期,是他们探索IT世界的黄金时期。本文将为准IT新生们提供一份全面的预习指南,帮助他们为未来的学习和职业生…...
HarmonyOS开发:循环渲染ForEach
需求: 创建多个列表组件,并实现点赞功能 语言: ArkTS 平台: DevEco Studio ForEach 接口描述 ForEach( arr: Array, itemGenerator: (item: Object, index: number) > void, keyGenerator?: (item: Object, index: number) &…...
构建工程化:多种不同的工程体系如何编写MakeFile
源码分析 核心MakeFile 这个 Makefile 是一个复杂的构建脚本,用于管理和构建一个大型项目。它包括多个目标、条件判断和递归调用 make 命令来处理多个子项目和子目录。让我们逐部分进行详细解析。 伪目标和变量定义 .PHONY: all clean install build test init.…...
聚焦从业人员疏散逃生避险意识能力提升,推动生产经营单位每年至少组织开展(疏散逃生演练,让全体从业人员熟知逃生通道、安全出口及应急处置要求,形成常态化机制。
聚焦从业人员疏散逃生避险意识能力提升,推动生产经营单位每年至少组织开展(疏散逃生演练,让全体从业人员熟知逃生通道、安全出口及应急处置要求,形成常态化机制。完整试题答案查看 A.三次B.两次C.一次 综合运用“四不两直”、明察暗访、 ()、…...
【手机取证】如何使用360加固助手给apk加固
文章关键词:手机取证、电子数据取证、数据恢复 一、前言 APP加固是对APP代码逻辑的一种保护。原理是将应用文件进行某种形式的转换,包括不限于隐藏,混淆,加密等操作,进一步保护软件的利益不受损坏,下面给…...
Vue的介绍
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
MySql数据库常用指令合集
MySql数据库常用指令合集 一、创建数据库db11.创建表 字段---表头 student_no,username,sex2.新增单条插入多条插入3.删除4.更新5.查询5.1.查询该表全部信息5.2.查询该表中username,并且要求名字为zhangsan性别女,还可以用(or) 6.…...
ArcGIS Pro SDK (七)编辑 13 注解
ArcGIS Pro SDK (七)编辑 13 注解 文章目录 ArcGIS Pro SDK (七)编辑 13 注解1 注释构建工具2 以编程方式启动编辑批注3 更新批注文本4 修改批注形状5 修改批注文本图形6 接地到网格 环境:Visual Studio 2022 .NET6 …...
模拟面试001-Java开发工程师+简历+问题+回答
模拟面试001-Java开发工程师简历问题回答 目录 模拟面试001-Java开发工程师简历问题回答面试简历面试官题问求职者回答1. 关于Java编程和技术栈2. 关于XX在线购物平台项目3. 关于XX企业资源规划系统项目4. 团队协作与项目管理5. 个人发展与职业规划 参考资料 面试简历 **个人信…...
微信小程序 ——入门介绍及简单的小程序编写
目录 一、小程序入门 1.1 什么是小程序 1.2 小程序的优点 1.3 小程序注册 1.4 安装开发工具 1.5 创建第一个小程序 二、小程序目录结构及入门案例 2.1 目录结构 2.2 入门案例 2.2.1 创建界面 2.2.2 设置标题 2.2.3 编写WXML文件 2.2.4 编写JS文件 2.2.5 编写WXSS…...
ubuntu20.04安装lio-sam
1、依赖功能包安装 sudo apt install ros-noetic-robot-state-publisher sudo apt-get install ros-noetic-robot-localization libmetis-dev 2、boost版本 boost版本查看:cat /usr/include/boost/version.hpp | grep "BOOST_LIB_VERSION" boost版本为1.…...
Kafka系列之Kafka知识超强总结
一、Kafka简介 Kafka是什么 Kafka是一种高吞吐量的分布式发布订阅消息系统(消息引擎系统),它可以处理消费者在网站中的所有动作流数据。 这种动作(网页浏览, 搜索和其他用户的行动)是在现代网络上的许多社…...
第32讲:K8S集群与Cephfs文件系统集成
文章目录 1.在K8S环境下RBD与Cephfs的使用对比2.Cephfs环境介绍3.在Ceph集群中为K8S创建单独Cephfs文件系统和认证用户3.1.创建一个K8S使用的Cephfs文件系统3.2.将创建的Cephfs文件系统挂载到本地路径3.3.创建K8S连接Ceph集群使用的认证用户 4.K8S PV存储卷使用Cephfs文件系统4…...
服务器数据恢复—DS5300存储raid5阵列数据恢复案例
服务器存储数据恢复环境: 某单位一台某品牌DS5300存储,1个机头4个扩展柜,50块硬盘组建2组RAID5磁盘阵列(一组raid5阵列有27块成员盘,存放Oracle数据库文件;另外一组raid5阵列有23块成员盘)。存储…...
使用Ubuntu 22.04安装Frappe-Bench【二】
系列文章目录 第一章 使用VMware创建Ubuntu 22.04【一】 文章目录 系列文章目录前言什么是Frappe-Bench?使用安装ERPNext能实现什么效果? 官网给了一个说明 一、使用Ubuntu 22.04安装Frappe-Bench一、安装要求二、安装命令三、 可能出现问题 总结 前言 …...
MySQL增删改查
1.创建数据库: 使用CREATE DATABASE语句 CREATE DATABASE school;show databases; 列出MySQL数据库管理系统的数据库列表 2.切换数据库: 使用USE语句选择要操作的数据库 USE school;select database (); 当前所在库mysql> select…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...




