动态规划——背包问题(01,完全,多重)

一、01背包问题

        1.题目描述

        有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,价值是 wi。

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

         01背包问题特点:每个物品只能用一次,只能选择或者不选择

        2.动态规划思想

        动态规划就是需要解决子问题,再通过状态转移方程拓展至整体最优。即需要满足:问题的最优解中包含的子问题也是最优的。

        定义 F[i][j] :当前背包容量为 j ,考虑前 i 个物品的最佳组合对应的价值。

当考虑背包容量为 j ,前 i 个物品的选择时,有两种想法:

        ① 不选择第 i 件 物品 则 F[i][j]=F[i-1][j]

        ② 选择第 i 件 物品,则需要考虑到剩余的背包容量 j - w[ i ] :

                                ​​​​​​​        F[i][j]=F[i-1][j-w[i]]+v[i]

最终状态转移方程:

        j<w[i] \, \, \, \, \, \, \, \, F[i][j]=F[i-1][j]

        j>=w[i] \, \, \, \, \, \, \, \, \, \, \, \, F[i][j]=max(F[i-1][j],F[i-1][j-w[i]]+v[i])

        由于状态转移过程F[i][j]都是由原先的状态得到的,因此思想成立。

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1010;
int f[N][N];
int v[N], w[N];
int n, m;
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>w[i]>>v[i];
	f[0][0]=0;
	for(int i=1;i<=n;i++)
		for(int j=0;j<=m;j++)
		{
			if(j<w[i])  f[i][j]=f[i-1][j];
			if(j>=w[i]) f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
		}
	cout<<f[n][m]<<endl;
	return 0;
}

         3. 01背包问题的探索

        在上述状态转移方程的过程中可以发现,在每次状态更新后,之前存储的数据不会再次用到,从而造成了空间上的浪费,可以将上述情况的二维数组压缩成一维数组,这时的数组就是动态变化的了

        与二维数组不同的是,在第二次循环过程中,背包容量的循环量应当从大到小(m->w[i])避免同一件物品被反复选择。 例如:

        当一件物品的体积为 1  价值为 10,当背包容量的循环量从小到大时, 运行F[1]=10,循环继续进行,F[2]=max(F[2],F[2-1]+10)=20。 即选择该物品两次,与01背包问题仅有一件商品不符,该方法适用于完全背包问题(同一件商品可以取多次)

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1010;
int f[N];
int v[N], w[N];
int n, m;
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>w[i]>>v[i];
	f[0][0]=0;
	for(int i=1;i<=n;i++)
	for(int j=m;j>=w[i];j--)  // 从后往前,避免同一件商品反复选择(01背包)
	{
		f[j]=max(f[j],f[j-w[i]]+v[i]);
	}
	cout<<f[m]<<endl;
	return 0;
}

二、完全背包问题

        题目描述

         有 N 件物品和一个容量是 V 的背包。每件物品数量为无限个。第 i 件物品的体积是 vi,价值是 wi。

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

        与01背包问题的唯一区别在于:完全背包的物品数量可以取无限个

        在01背包问题的讲述过程中已经明确解释了完全背包问题的解法:在01背包一维数组的情况下,将背包容量的循环量从小到大遍历,在数组不断更新的情况下能够让某件物品多次装入。

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1010;
int f[N];
int v[N], w[N];
int n, m;
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>w[i]>>v[i];
	f[0][0]=0;
	for(int i=1;i<=n;i++)
	for(int j=w[i];j<=m;j++)  // 从前往后,能够让某件物品多次选择(完全背包问题)
	{
		f[j]=max(f[j],f[j-w[i]]+v[i]);
	}
	cout<<f[m]<<endl;
	return 0;
}

三、多重背包问题  

        1.题目描述

        有 N 件物品和一个容量是 V 的背包。第 i 件物品的体积是 vi,价值是 wi,数量是 ki。

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

        与前两种背包问题的联系:01背包和完全背包都是对于某种情况的极端,而多重背包问题则是介于二者之间,每个物品可以取不同个数的情况。

         根据多重背包与01背包,完全背包的关系,可以得出一个简单的想法:

        ①. 把多重背包问题变成01背包问题:

        即当某个物品有k个时,可以看作存在相同的体积,价值的k个不同的物品,这样就可以存在每个物品取一个或者取几个的情况。

        或者再利用一层循环 k 枚举该物品取的次数,保证存在取多次的情况。

        这种想法显然成立,但只适用于数量较少的情况,如果每种物品的数量变大,存在超时的情况,因此不是最优的解法

       ②.联系完全背包问题

        当背包不能装在某种物品的全部数量时,即(V<w[i]*k),则此时一定不能取完,可以看作完全背包问题,此时只需要简单的讨论即可。

        将多重背包转化成01背包和完全背包的结合只能进行小优化。

        2.多重背包问题的优化

        ① 二进制优化

                例如想要取512件物品时,按照转化成01背包问题,需要从第一件枚举512件,而采用二进制的想法,把每次取物品的件数分为1,2,4,8........256.512...2^n,枚举9次就取到512件了,此外每个数都可以用二进制数的组合来表示,例如 10=1+2+4+3   15=1+2+4+8

k=1;cnt=0;
while(k<=s)    //k为枚举个数,s为物品总件数
{
	v[++cnt]=k*a;
	w[cnt]=k*b;
	s-=k;       //总物品数减去合成数
	k*=2;       //k倍增
}
if(s)// s有剩余,将剩余件数合成为新个体
{
	v[++cnt]=s*a;
	w[cnt]=s*b;
}

 将每种物品的 k 都经过上述过程,构造出两个数组(存储有二进制数的数据)价值数组和重量数组,再通过01背包的思想,即可解决问题。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据分析之Tebleau可视化:树状图、日历图、气泡图

树状图&#xff08;适合子分类比较多的&#xff09; 1.基本树状图的绘制 同时选择产品子分类和销售金额----选择智能推荐----选择树状图 2.双层树状图的绘制 将第二个维度地区拖到产品分类的下面---大的划分区域是上面的维度&#xff08;产品分类&#xff09;&#xff0c;看着…

cmake进阶:文件操作

一. 简介 前面几篇文章学习了 cmake的文件操作&#xff0c;写文件&#xff0c;读文件。文章如下&#xff1a; cmake进阶&#xff1a;文件操作之写文件-CSDN博客 cmake进阶&#xff1a;文件操作之读文件-CSDN博客 本文继续学习文件操作。主要学习 文件重命名&#xff0c;删…

C++引用2

什么是引用变量&#xff1f; 引用实际上是已定义变量的别名&#xff0c;使一个变量拥有多个名字 c给&#xff06;符号赋予了另一个意义&#xff0c;将其用来声明引用 int a9;int&ba; 此时b成为a的一个别名&#xff0c;a就是b,b就是a.它们均指向同一片内存 int a99; in…

虚拟键代码

虚拟键代码 虚拟键码 (Winuser.h) - Win32 apps | Microsoft Learn 在Windows操作系统中&#xff0c;虚拟键代码&#xff08;Virtual-Key Codes&#xff09;是一组用来表示键盘上按键的数值。这些代码通常用于Windows API函数&#xff0c;以便程序能够识别和处理键盘输入。 虚拟…

OSEK任务管理

1 前言 RTOS通过任务&#xff08;task&#xff09;来组织应用层程序框架&#xff08;framework&#xff09;&#xff0c;支持任务的并发和同步执行&#xff08;concurrent and asynchronous execution of tasks&#xff09;&#xff0c;并通过调度器&#xff08;scheduler&…

[方法] Unity 实现仿《原神》第三人称跟随相机 v1.1

参考网址&#xff1a;【Unity中文课堂】RPG战斗系统Plus 在Unity游戏引擎中&#xff0c;实现类似《原神》的第三人称跟随相机并非易事&#xff0c;但幸运的是&#xff0c;Unity为我们提供了强大的工具集&#xff0c;其中Cinemachine插件便是实现这一目标的重要工具。Cinemachi…

超分辨率重建——BSRN网络训练自己数据集并推理测试(详细图文教程)

目录 一、BSRN网络总结二、源码包准备三、环境准备3.1 报错KeyError: "No object named BSRN found in arch registry!"3.2 安装basicsr源码包3.3 参考环境 四、数据集准备五、训练5.1 配置文件参数修改5.2 启动训练5.2.1 命令方式训练5.2.2 配置Configuration方式训…

vivado UltraScale 比特流设置

下表所示 UltraScale ™ 器件的器件配置设置可搭配 set_property <Setting> <Value> [current_design] Vivado 工具 Tcl 命令一起使用。

翻译《The Old New Thing》 - What’s the point of DeferWindowPos?

Whats the point of DeferWindowPos? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20050706-26/?p35023 Raymond Chen 在 2005年7月6日 DeferWindowPos 的作用是什么&#xff1f; 简要 文章讨论了 DeferWindowPos 函数的用途&#xff…

LangChain框架学习总结

目录 一、简介 二、概念 三、组件具体介绍 3.1 Models 3.1.1 LLMs 3.1.2 Chat Models 3.1.3 Text Embedding Modesl 3.1.4 总结 3.2 Prompts 3.2.1 LLM Prompt Template 3.2.1.1 自定义PromptTemplate 3.2.1.2 partial PromptTemplate 3.2.1.3 序列化PromptTemplat…

IMEI引起的无法驻网问题

这篇内容没什么意思&#xff0c;仅仅是做个简单记录。 问题不复杂&#xff0c;场景很简单&#xff0c;如上图&#xff0c;UE在进行LTE attach过程时&#xff0c;在送完NAS security mode complete后&#xff0c;就立刻收到了网络attach reject 带cause 6 Illegal ME&#xff0c…

Chrome浏览器安装React工具

一、如果网络能访问Google商店&#xff0c;直接安装官方插件即可 二、网络不能访问Google商店&#xff0c;使用安装包进行安装 1、下载react工具包 链接&#xff1a;https://pan.baidu.com/s/1qAeqxSafOiNV4CG3FVVtTQ 提取码&#xff1a;vgwj 2、chrome浏览器安装react工具…

设置定位坐标+请按任意键继续

设置定位坐标 目的 在编程和游戏开发中&#xff0c;设置定位坐标的目的是为了确定对象在屏幕或游戏世界中的具体位置。坐标通常由一对数值表示&#xff0c;例如 (x, y)&#xff0c;其中 x 表示水平位置&#xff0c;y 表示垂直位置。设置定位坐标的目的包括&#xff1a; 1. **精…

【云原生】Pod 的生命周期(二)

【云原生】Pod 的生命周期&#xff08;一&#xff09;【云原生】Pod 的生命周期&#xff08;二&#xff09; Pod 的生命周期&#xff08;二&#xff09; 6.容器探针6.1 检查机制6.2 探测结果6.3 探测类型 7.Pod 的终止7.1 强制终止 Pod7.2 Pod 的垃圾收集 6.容器探针 probe 是…

MATLAB 变换

MATLAB 变换&#xff08;Transforms&#xff09; MATLAB提供了用于处理诸如Laplace和Fourier变换之类的变换的命令。转换在科学和工程中用作简化分析和从另一个角度查看数据的工具。 例如&#xff0c;傅立叶变换允许我们将表示为时间函数的信号转换为频率函数。拉普拉斯变换使…

Linux驱动开发——(十一)INPUT子系统

目录 一、input子系统简介 二、input驱动API 2.1 input字符设备 2.2 input_dev结构体 2.3 上报输入事件 2.4 input_event结构体 三、代码 3.1 驱动代码 3.2 测试代码 四、平台测试 一、input子系统简介 input子系统是管理输入的子系统&#xff0c;和pinctrl、gpio子…

#9松桑前端后花园周刊-React19beta、TS5.5beta、Node22.1.0、const滥用、jsDelivr、douyin-vue

行业动态 Mozilla 提供 Firefox 的 ARM64 Linux二进制文件 此前一直由发行版开发者或其他第三方提供&#xff0c;目前Mozilla提供了nightly版本&#xff0c;正式版仍需要全面测试后再推出。 发布 React 19 Beta 此测试版用于为 React 19 做准备的库。React团队概述React 19…

【driver4】锁,错误码,休眠唤醒,中断,虚拟内存,tasklet

文章目录 1.互斥锁和自旋锁选择&#xff1a;自旋锁&#xff08;开销少&#xff09;的自旋时间和被锁住的代码执行时间成正比关系2.linux错误码&#xff1a;64位系统内核空间最后一页地址为0xfffffffffffff000~0xffffffffffffffff&#xff0c;这段地址是被保留的&#xff0c;如果…

全新桥隧坡安全监测解决方案,24h监测效率提升30%

4月26日&#xff0c;交通运输部党组书记、部长李小鹏在部务会上强调&#xff0c;要高度重视公路桥梁隧道结构监测工作&#xff0c;抓紧推进公路桥梁隧道结构监测系统建设&#xff0c;进一步健全完善公路桥梁隧道结构监测长效运行机制。 中海达积极参与公路桥梁隧道结构监测工作…

触摸OpenNJet,感悟云原生

小程一言 云原生使得应用充分利用云计算、容器化和微服务架构等现代技术来构建和运行应用程序。 云原生技术的用处在于提高应用程序的可靠性、可伸缩性和灵活性&#xff0c;加快开发和部署速度&#xff0c;降低成本&#xff0c;提升整体的效率和竞争力。通过采用云原生技术&a…