【背包题解】DP代表了走到阶段i 的所有路线的最优解

news2024/11/28 0:41:46

1889:【提高】多重背包(2)

二维费用背包

2075 - 最大卡路里

1928 - 采购礼品

感谢



背包容量:(c)

6

重量

weight

2

2

4

6

2

1

2

3

4

5

价值

value

3

6

5

5

8

1

2

3

4

5

wv
dp数组:记录有i件物品,背包容量为j的情况下,最大价值
nameweightvalue123456
a23033333
b2606/66+dp[i-1][j-w[i]]=999
c45
d65
e28

第i件物品  

w[i]>c:放不下,最大价值=i-1件物品讨论时的最大价值

选:剩余容量=c-w[i],最大价值=v[i]+(i-1件物品,容量在 c-w[i]的情况下最大价值)

w[i]<=c:放得下

不选:最大价值=i-1件物品讨论时的最大价值

dp[i][j]

w[i]>c:放不下,最大价值 =dp[i-1][j]

选,最大价值 =v[i]+ dp[i-1][c--w[i]]

w[i]<=c:放得下,最大价值

不选,最大价值 =dp[i-1][j]

动态转移方程:

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

1889:【提高】多重背包(2)

题目描述

有 N 种物品和一个容量是 V的背包。

第 ii种物品最多有 si​ 件,每件体积是 vi​,价值是 wi​ 。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。

输出最大价值。

关于 DP要理解的关键点:

1 DP的本质

求有限的集合中的最值(个数)

本质上,DP代表了走到阶段i 的所有路线的最优解

2 DP需要思考的点:

(1)DP 的状态是什么?状态要求什么:最大、最小、数量?

(2)DP   的状态计算?

状态转义方程;

求解方法: a 、递推  b、考虑阶段i  (最后一个阶段的值)的值是如何得来的

(3)DP   的边界是什么?

关键术语:阶段、状态、决策(状态转移方程)、边界;

以数塔问题(1216:【基础】数塔问题)为例,理解DP 的本质,再理解01背包的本质 (1282:【提高】简单背包问题);

经典的 DP模板题要熟练掌握,熟记状态转义方程!

本题解题的关键点:二进制优化(类似压缩的思想)

( 1 ) 有n 个不同的物品,要讨论2"种选择的可能(每个物品选或者不选);

(2)一个物品有n 件,虽然要讨论2"种选择的可能,但由于n 个物品是一样的,那么 就减少了讨论数量,比如:有4个物品,如果是不同物品的选2个,选12、23是不同的 选择,但如果是相同的物品,选哪两个就都是一样的了。

因此,n 个物品,要讨论的可能就分别是:选0个、选1个、选2个、选3个…选n 个。 (3)要将0~n 个不同的选择表达出来,比较简单的方法是将n 二进制化。

比如:整数7,只需要用124三个数任意组合,就能组合出0~7这8种可能。

再比如:整数10,只需要用1243(注意最后一个数),就能组合出0~10这11种可 能,这样 n 这个值就被二进制化了。

因此如果要讨论10个一样的物品,就转化为讨论4个不同的物品了;而n 个一样的物 品,就转化为log₂n 个不同的物品进行讨论。

dp[j]=max{dp[j],dp[j-w[i]]+v[i]}

#include <bits/stdc++.h>
using namespace std;

const int N=20010;
int v[N],w[N],dp[2010];
int n,m;//n种物品,背包容量为m
int vi,wi,si;
int k=0;
int main() {
	cin>>n>>m;
	for(int i=1; i<= n; i++) {
		cin>>vi>>wi>>si;
		/*对si二进制化,比如:
		有10件一样的物品我们转换为有4件不同的物品:1 2 4 3
		这4种物品的体积分别是:1*vi 2*vi 4*vi 3*vi*/
		int t=1;//权重,表示2的次方
		while(t<= si) {
			k++;
			v[k]= t* vi;
			w[k]=t* wi;
			si =si-t;
			t=t*2;
		}
//如果二进制化有剩余,存入
		if(si >0) {
			k++;
			v[k]= si * vi;
			w[k]= si * wi;
		}
	}

//01 背包
	for(int i=1; i<= k; i++) {
		for(int j= m; j >= v[i]; j--) {
			dp[j]= max(dp[j],dp[j-v[i]]+w[i]);
		}
	}
	cout<<dp[m];
	return 0;
}

二维费用背包

二维费用的背包问题是指:对于每件物品,具有两种不同的费用;选择这件物品必须同 时付出这两种代价;对于每种代价都有一个可付出的最大值(背包容量)。问怎样选择物品 可以得到最大的价值。设这两种代价分别为代价1和代价2,第i 件物品所需的两种代价分  v[i]   w[i]

两种代价可付出的最大值(两种背包容量)分别为maxv  maxw, 物品的价值为c[i]

解决方法: 费用加了一维,只需状态也加一维即

 f[i][j][k]       表示前i 件物品付出两种代价分别,背包体积j,  背包的承重为k 时可

获得的最大价值。

状态转移方程就是:

f[i][j][k]=max(f[i-1][j][k],f[i-1][j-v[i]][k-w[i]]+c[i])

空间优化后,可以用二维数组求解。

f[j][k]=max(f[j][k],f[j-v[i]][k-w[i]]+c[i])

2075 - 最大卡路里

题目描述

神州飞船准备运送一批食品到太空站,该飞船能够运送食品的重量、体积都有严格的限制。

现已知 nn 件完全不同的食品,每种食品的重量、体积及该食品能够提供的卡路里的值,请你编程计算出,该飞船最多能够运送多少卡路里的食物?

#include <bits/stdc++.h>
using namespace std;

const int N=410;
int dp[N][N];//代表求解体积为j,重量为k时能够得到的最大价值
int n,v,w,c;
int maxv,maxw;//背包的上限
int main() {
	cin>>maxv>>maxw;
	cin>>n;
	for(int i=1; i<= n; i++) {
		cin>>v>>w>>c;
		//01 背包
		//从最大体积~当前物品体积降序循环,同理重量也要降序循环
		for(int j= maxv; j >= v; j--) {
			for(int k=maxw; k >= w; k--) {
				dp[j][k]= max(dp[j][k],dp[j-v][k-w]+c);
			}
		}
	}
	cout<<dp[maxv][maxw];//最大价值
	return 0;
}

1928 - 采购礼品

题目描述

王老师来到商店为同学们采购礼品。

这家店有 n 种礼品(编号是 1∼n ),每种礼品只有 1 件。老板为了促销,对礼品进行搭配销售,有关联性的礼品必须都要采购(奇怪的规定),比如 1 号礼品和 3号礼品搭配了,3 号和 8 号礼品搭配了,那么王老师想要买 1 号礼品的话,就需要把 3 号和 8 号礼品都买了。

现给定每种礼品的价钱和价值,请问在有限的钱 w 的情况下,能够买到礼品的最大价值是多少?

输入

第一行输入三个整数,n,m,w,表示有n 种礼品,m 个搭配和你现有的钱的数目。

第二行至 n+1 行,每行有两个整数,c、d,表示第 ii 种礼品的价钱和价值。(1≤c,d≤10^5)

第 n+2 至 n+1+m 行 ,每行有两个整数,u、v,表示 u 号礼品和 vv 号礼品是有关联的,已经形成搭配销售的关系。

数据范围:

1≤n,w≤10^4,0≤m≤5 *10^3。

输出

一行,表示可以获得的最大价值。

样例

输入

5 3 10
3 10
3 10
3 10
5 100
10 1
1 3
3 2
4 2

输出

1

典型的01背包,但要求同一组的物品都要购买。我们可以采用并査集将同一组有关系的礼品的价值、价格汇总到该集合的根节点上,这样就保证了一个集合中的礼品都购买的情况。

它解决的是在有限的预算 w 下,如何选择一组关联的礼品(根据提供的搭配信息),使得这些礼品的价值总和最大。

  1. 定义了几个数组:f 用于并查集,存储物品之间的关系;qv 分别存储物品的价钱和价值;dp 用于动态规划,记录在给定背包容量下的最大价值。

  2. 首先通过并查集对具有关联关系的物品进行合并,确保在考虑搭配时,每个组合中的所有物品都被视为一个整体。

  3. 然后,遍历所有物品,如果某物品不是其自身的根节点,说明这个物品已经被包含在某个组合中,需要更新根节点的价钱和价值。

  4. 接着进行动态规划计算。从背包容量 w 到每种物品的价钱(降序),尝试是否可以添加当前物品,如果可以,更新背包的最大价值。

  5. 最后,输出在给定预算 w 下可以获得的最大价值。

  6. 王老师需要在有限的预算 w 下,选择价值最高的礼品组合,但受到了一些特定的搭配规则影响,即如果一种礼品被选中,与其搭配的相关礼品也必须被同时购买。

  7. 具体步骤如下:

  8. 理解问题: 首先,我们需要知道每种礼品的价值(d)和价格(c),以及哪些礼品之间存在强制搭配关系(由uv表示)。这是一个二维背包问题,因为搭配关系限制了我们不能单独选择某件礼品。

  9. 模型构建: 可以考虑使用动态规划的方法,比如创建一个二维数组 dp[i][j],其中 i 代表剩余的预算,j 代表剩余的可选礼品数量。dp[i][j] 表示在剩余预算 i 和可以选择的礼品数量 j 下,能获得的最大价值。

  10. 状态转移: 对于每个礼品 k,有两种情况:选择它(增加价值 d[k] 但减少可用预算 c[k]),或不选择它。根据这两种情况,更新 dp 数组。

  11. 处理搭配关系: 在更新 dp 时,要考虑已有的搭配关系。如果礼品 kl 搭配,意味着在包含 k 的情况下,l 也会被强制选择。因此,我们需要更新 dp 时包括这种情况。

  12. 寻找最大价值: 最终的答案就是 dp[w][n],即在预算 w 和所有礼品都可选的情况下,能获得的最大价值。

  13. 输出结果: 返回计算得到的最大价值作为答案。

#include <bits/stdc++.h>
using namespace std;

int f[10100];//存储物品之间的关系
int q[10100],v[10100];//价钱、价值
int dp[10100];//以拥有的钱来定义背包容量
//查:查询元素的根
int find(int x) {
	return f[x]==x?x:f[x]=find(f[x]);
}
//并:合并元素xy
void merge(int x,int y) {
	int fx = find(x);
	int fy = find(y);
	if(fx != fy) {
		f[fx]=fy;
	}
}
int main() {
	int n,m,w;
	cin>>n>>m>>w;//n个物品的价钱和价值
	for(int i = 1; i<= n; i++) {
		cin>>q[i]>>v[i];
		//并查集初始化
		f[i]= i;
	}
	//m个物品的关系
	int x,y;
	for(int i = 1; i<= m; i++) {
		cin>>x>>y;
		merge(x,y);
	}
	//将有关系的物品合并到这组物品的根上司
	for(int i = 1; i<= n; i++) {
		//该物品不是根,则将价钱和价值都合并到根上
		if(f[i] != i) {
			q[find(i)]+=q[i];
			v[find(i)]+=v[i];
			//将该组物品的价钱和价值清零
			q[i]=0;
			v[i]=0;
		}
	}
	//01背包计算结果
	for(int i = 1; i <= n; i++) {
		//从背包容量(有多少钱)~该物品的价钱降序
		for(int j= w; j >= q[i]; j--) {
			dp[j] = max(dp[j],dp[j-q[i]]+v[i]);
		}
	}
	cout<<dp[w];

	return 0;
}

 

感谢

如若本文对您的学习或工作有所启发和帮助,恳请您给予宝贵的支持——轻轻一点,为文章点赞;若觉得内容值得分享给更多朋友,欢迎转发扩散;若认为此篇内容具有长期参考价值,敬请收藏以便随时查阅。

每一次您的点赞、分享与收藏,都是对我持续创作和分享的热情鼓励,也是推动我不断提供更多高质量内容的动力源泉。期待我们在下一篇文章中再次相遇,共同攀登知识的高峰!

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

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

相关文章

09-axios在Vue中的导入与配置

09-axios 前言首先简单了解什么是Axios&#xff1f;以上完成后就可以使用了 前言 我们接着上一篇文章 08-路由地址的数据获取 来讲。 下一篇文章 10-vuex在Vue中的导入与配置 首先简单了解什么是Axios&#xff1f; Axios是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端…

【Linux系统】Linux 命令行查看当前目录的总大小/总磁盘空间

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-06-22 0…

IDEA快速入门06-插件

六、插件 6.1 IDEA插件介绍和管理 手动演示IDEA中怎么下载插件&#xff0c;管理插件等。 File -> Settings -> Plugins 6.2 Alibaba Java Coding Guidelines 6.2.1 实时检查 6.2.2 主动检查 选中【项目名称】或者【某一个具体类】&#xff0c;右键点击【编码规约扫…

2022年大作业参考报告-使用C++语言开发小学生成绩管理系统、中学生成绩管理系统、大学生成绩管理系统【240621更新】

背景&#xff1a; 目录 第一章 需求分析 2 1.1 问题描述 2 6.1 功能需求 2 6.2 开发环境 2 6.3 开发过程 2 第二章 概要设计 3 2.1 总体设计 3 2.2 类的定义 3 2.3 接口设计 5 2.4 运行界面设计 6 第三章 详细设计 …

Kafka第一篇——内部组件概念架构启动服务器zookeeper选举以及底层原理

目录 引入 ——为什么分布式系统需要用第三方软件&#xff1f; JMS 对比 组件 架构推演——备份实现安全可靠 &#xff0c; Zookeeper controller的选举 controller和broker底层通信原理 BROKER内部组件 ​编辑 topic创建 引入 ——为什么分布式系统需要用第三方软件&#…

【知识图谱】基于neo4j开发的信息化文档分析系统(源码)

一、项目介绍 一款全源码&#xff0c;可二开&#xff0c;可基于云部署、私有部署的企业级知识库云平台&#xff0c;一款让企业知识变为实打实的数字财富的系统&#xff0c;应用在需要进行文档整理、分类、归集、检索、分析的场景。 为什么建立知识库平台&#xff1f; 助力企业…

R语言——数据与运算

练习基本运算&#xff1a; v <- c(2,4,6,9)t <- c(1,4,7,9)print(v>t)print(v < t)print(v t)print(v!t)print(v>t)print(v<t) v <- c(3,1,TRUE,23i)t <- c(4,1,FALSE,23i)print(v&t)print(v|t)print(!v)v <- c(3,0,TRUE,22i)t <- c(1,3,T…

O2OA的数据库数据库配置-使用不同用户访问Oracle时报错-表或视图不存在

在使用Oracle数据库时&#xff0c;多个O2OA服务器同一个Oracle实例中使用不同的用户启动时&#xff0c;可能会遇到数据库访问的错误。本篇阐述此类问题以及解决方案。 一、先决条件&#xff1a; 1、O2OA已经下载并且解压到指定的目录&#xff1b; 2、Oracle数据库已经完成安…

什么是 vCPU?有什么作用

vCPU 是物理 CPU 的虚拟化版本&#xff0c;是云计算的基本组成部分。这些虚拟化计算单元的一大优势是其良好的可扩展性&#xff0c;这也是它们在云托管中发挥重要作用的原因。 vCPU 有什么作用? vCPU(虚拟中央处理器)是物理CPU的虚拟化变体。换句话说&#xff0c;vCPU 是虚拟机…

数据库系统概念(第七周 第二堂)(E-R模型转关系模式)

前言 前一堂课我们深入研究了E-R模型的画法和要点&#xff0c;学习E-R模型肯定是为了给数据库表格设计提供帮助。数据库表格设计就是关系模式设计&#xff0c;数据库表就是关系模式的实例化。所以本堂课&#xff0c;我们来看E-R模型如何转为关系模式。 转化原则 转化步骤 转…

1 矢量分析与场论

目录 场就是函数 矢量函数 场的概念 矢量运算 矢量加法与矢量减法 矢量点乘 矢量叉乘 矢量混合积 场的分析方法 等值面 矢量线 场就是函数 矢量函数 场的概念 矢量运算 矢量加法与矢量减法 矢量点乘 矢量叉乘 矢量混合积 场的宏观分析 等值面 等值面之间不会…

python19 异常处理

python19 异常处理 代码 异常处理 result 0; try:num1 int(input(请输入一个整数:))num2 int(input(请输入一个整数:))result num1 / num2 except ZeroDivisionError:print(除数不能为0) except ValueError:print(不能将字符串转成整数) except BaseException:print(未知异…

远程问诊优劣势并存,满足医患需求更关键

随着互联网技术的快速发展&#xff0c;如今其已经融入到了这个社会的各个领域&#xff0c;就连医疗行业也不例外。尤其是近几年在国家政策的支持和疫情的推动下互联网医疗平台更是如雨后春笋般冒了出来&#xff0c;并且这些平台中有不少还开发了远程问诊功能&#xff0c;对于此…

CRMEB 多店商品详情页装修说明

一、功能介绍 商家可调整商品详情各板块样式&#xff0c;可根据不同的需求开启或关闭单独的板块 二、操作流程 装修 > 商品详情 三、功能说明 1、商品信息 可控制商品详情页面商品信息的显示与隐藏 2、会员信息&#xff0c;排行榜 控制商品详情页面会员信息及排行榜的…

编译原理-各章典型题型+思路求解

第2章文法和语言习题 基础知识&#xff1a; 思路&#xff1a; 基础知识&#xff1a; 思路&#xff1a; 基础知识&#xff1a; 编译原理之 短语&直接短语&句柄 定义与区分_编译原理短语,直接短语,句柄-CSDN博客 思路&#xff1a; 题目&#xff1a; 基础解释&#xff1a…

Javase.认识异常

认识异常 【本章目标】1. 异常的概念与体系结构1.1 异常的概念1.2 异常的体系结构1.3 异常的分类 2. 异常的处理2.1 防御式编程2.2 异常的抛出2.3 异常的捕获2.3.2 try-catch捕获并处理2.3.3 finally2.4 异常的处理流程 3. 自定义异常类 【本章目标】 异常概念与体系结构异常的…

04-echarts-立体柱状图扩展

柱状图扩展 一、前言二、思路1、新增面①、在drawShape方法中&#xff0c;新增一个实际左侧面&#xff0c;②、 在drawShape方法中&#xff0c;新增一个实际右侧面&#xff0c;③ 绘制 2、新增series对象① 添加实际值的左侧面和右侧面 三、效果图 一、前言 事情是这样子的&am…

java技术专家面试指南50问【java学习+面试宝典】(十)

ConcurrentHashMap实现原理 JDK1.7 : 【数组&#xff08;Segment&#xff09; 数组&#xff08;HashEntry&#xff09; 链表&#xff08;HashEntry节点&#xff09;】 ConcurrentHashMap&#xff08;分段锁&#xff09; 对整个桶数组进行了分割分段(Segment)&#xff0c;每一…

IDEA集成Docker实现快捷部署

本文已收录于专栏 《运维》 目录 背景介绍优势特点操作步骤一、修改Docker配置二、配置Docker插件三、编写Maven插件四、构建Docker镜像五、创建Docker容器 总结提升 背景介绍 在我们手动通过Docker部署项目的时候&#xff0c;都是通过把打包好的jar包放到服务器上并且在服务器…

AI穿戴设备是未来手机的终结者?中国AI商业化的未来预测

AI技术的发展正处于商业化应用的关键阶段&#xff0c;而中国在互联网时代已凭借商业化应用逆袭。AI算法大模型虽强大&#xff0c;但真正普惠民众需与设备深度结合。穿戴式智能设备就成为了新战场&#xff0c;AI算法与穿戴设备结合能释放更大工作效率。私人助理AI将成趋势&#…