C++动态规划(背包问题)

news2025/1/10 20:01:50

目录

一:动态规划是什么

二.动态规划的运用

(1).用动态规划解决重复子问题

(2).动态规划使用的条件与流程

Ⅰ.动态规划的使用条件:

Ⅱ.动态规划的使用流程

(3).背包问题

三.背包问题:

(1).0|1背包

Ⅰ.朴素方法:

Ⅱ.滚动数组优化 :

Ⅲ.一维数组:


一:动态规划是什么

计算机相对于人类来说的优势有三点,一点是他的运行速度,第二点是准确性,第三点则是处理问题的时候逻辑十分清晰。所以我们一般在编程时用的有两种方法,一是运用计算机的快速计算能力进行暴力枚举法、另一个则是将一个大问题分成小问题,求出所有小问题的答案再组合在一起得出正确答案的分解问题法。其中分解问题法需要能熟悉的掌握分解题目的方式以及能够熟练的运用递归,分治和贪心等算法。但他们各有他们的劣势。就比如贪心算法,在三角形中寻找最短的边的时候,他会在每一个节点是选择边较长的那一个。但是他不会考虑到较短的那条边连接的下一条边是否更长,所以贪心算法虽然时间复杂度较低,但他得出来的是较优解,而不是最优解。

举个例子:

货币面额有1,2,5,10,20,50,100,每种数量都无限多,现在给出金额n(1<=n<=1e6),求出构造金额n的最少货币数量

贪心策略:分成若干次选择,每一次选择比n小且最接近n的货币。

但是如果当n=7是,货币金额分别为3、1、4、5时,如果先选择5的话就没法凑出7。

如果我们将构造某个金额所需要的最少货币数量作为一个问题,并且用数组储存答案。那么在求解某个原问题的时候,我们只需要考虑原问题由哪一个子问题推出能得到更优解即可。

如本题:我们用f[i]表示金额为i的最少需要的硬币的总数量。

明显可以发现:f[1]=1 / f[2]=2 / f[3]=2 / f[4]=2 / f[5]=1 / f[6]=3 ......

而f[7]有多种组成,比如:

f[7]=f[6]+f[1]=f[5]+f[2]=f[4]+f[3]=f[5]+f[1]+f[1]......,我们从中选择一个解使得f[7]最小即可。像这样我们把每个子问题的解储存下来,最终可以知道原问题的解一定可以由子问题推出。将求解变成一个递推,与普通递推不一样的地方在于原问题可能会由多个子问题推出,我们选最优的即可。

这就是动态规划(DP)的基本思想,以空间换时间,存放各子问题的解以便能推出原问题。这样可以充分保证求解的正确性。具体讲解放在下一部分。

二.动态规划的运用

(1).用动态规划解决重复子问题

动态规划其实和分治算法的想法相同,保证可以通过子问题来推出原问题的最终答案,而且在处理重复子问题的时候非常的高效。我们在进行搜索剪枝的时候,对于无法避免的较多重复的子问题,我们通常采用记忆化的方式进行处理。但由于其使用了递归的方法,对于规模比较大的问题,他依旧会超时。但如果使用动态规划的话,因为其本质为递推,所以对于重复子问题可以进行高效的处理。另外我们还知道,子问题越多那么复杂度越高,如果我们将子问题的规模缩小(多个有相同性质的子问题合并视作一个),那么复杂度将会大大减小。

像上一道题一样,我们将所有金额为7的组合视作一个集合。集合的值为最少货币数量显然,集合的允许加入条件越宽松,那么重复子问题就越多,要处理的节点也就越少。

(2).动态规划使用的条件与流程

Ⅰ.动态规划的使用条件:

1.重复子问题:存在大量子问题进行了重复计算。

2.具备最优子结构:后面阶段的状态可以通过前面子问题状态推导出来。

3.无后效性:已经求解的子问题,不会再受到后续决策的影响。即从关系图上而言是一个DAG。

Ⅱ.动态规划的使用流程

1.划分子问题。即定义集合,描述状态。

2.确定状态转移方程。即子问题的解如何推出原问题

3.确定初始值

4.确定遍历顺序,保证求某问题时,其涉及到的子问题的解已经全部求出。即从小到大填出dp表

(3).背包问题

背包问题‌是一个经典的动态规划问题,它描述了一个旅行者有一个最多能装m公斤的背包,现在有n件物品,每件物品有各自的重量和价值。他的要求是选择装入背包的物品,使得背包内物品的总价值最大,同时不超过背包的容量限制。这个问题通常被称为0/1背包问题,因为每个物品只有两种选择:装入背包或不装入背包。

背包问题与动态规划算法是密不可分的,该算法通过构建一个表格来记录每个子问题的解,最终找到最优解。具体来说,对于每个物品i和背包的当前承重j,算法会考虑两种情况:将物品i放入背包(如果它的重量不超过j)或不放入背包。通过比较这两种情况下的价值,算法可以确定在当前承重下应该如何选择物品以达到最大价值。

三.背包问题:

(1).0|1背包

就如上面所说,0/1背包就是在动态规划的基础上进行选与不选。

例题:采药

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

请输出可以采到的草药的总最大值。

思路:

每加入一物品,dp[i]的值可能会产生变化。根据上一阶段的状态,从小到大进行更新当前阶段的状态,因此dp可以增加一个维度为:dp[i][j]表示第i个阶段,时间不超过j的最大价值。更新过程就是一个填表的过程。时间复杂度O(nT)

Ⅰ.朴素方法:

将所有信息输入到表格中,在循环中进行处理。空间复杂度(tn)

代码:

#include<bits/stdc++.h>
using namespace std;
int t,n,dp[1005][1005];
int main(){
	cin>>t>>n;
	for(int i=1;i<=n;i++){
		int a,b;cin>>a>>b;
		for(int j=0;j<=t;j++){
			if(j<a) dp[i][j]=dp[i-1][j];
			else dp[i][j]=max(dp[i-1][j-a]+b,dp[i-1][j]);
		}
	}
	cout<<dp[n][t];
	return 0;
}

Ⅱ.滚动数组优化 :

因为我们在更新表格的时候仅需要上一行表格,所以我们只需要两个数组进行存储。

代码:

#include<bits/stdc++.h>
using namespace std;
int f[2][10005],t,n,m;
int main(){
	cin>>t>>m;
	for(int i=1;i<=m;i++){
        int a,b;cin>>a>>b;
		for(int j=a;j<=t;j++){
			f[i%2][j]=f[(i-1)%2][j];
			f[i%2][j]=max(f[i%2][j],f[(i-1)%2][j-a]+b);
		}
	}
	cout<<f[m%2][t];
}

注:这是60分代码,本人目前还不知道哪错了,如有大佬知道错哪了,麻烦在评论区回复,万分感谢

Ⅲ.一维数组:

其实我们也可以用一维数组来表示,只需要从右侧开始这样的话在更新了后面的数据以后才会去修改前面的数据

代码:

#include<bits/stdc++.h>
using namespace std;
int t,m,dp[1005];
int main(){
	cin>>t>>m;
	for(int i=1;i<=m;i++){
		int a,b;cin>>a>>b;
		for(int j=t;j>=a;j--) dp[j]=max(dp[j],dp[j-a]+b);
	}
	cout<<dp[t];
	return 0;
}

此文章为笔记型,会随着时间而更新,望原谅

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

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

相关文章

IO进程(学习)2024.8.22

信号 信号函数 信号处理函数 #include <signal.h> sighandler_t signal(int signum, sighandler_t handler); 功能&#xff1a;信号处理函数 参数&#xff1a;signum&#xff1a;要处理的信号 handler&#xff1a;信号处理方式 SIG…

基于矢量控制器的PMSM永磁同步电机速度控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于矢量控制器的PMSM永磁同步电机速度控制系统simulink建模与仿真&#xff0c;仿真输出电机转速跟踪曲线&#xff0c;PID控制器输出曲线以及Te输出曲线。 2.系统仿真结果 &…

kafka的一个有趣问题(BUG)

这是我的第104篇原创文章 问题由来 在使用kafka时&#xff0c;创建topic&#xff0c;对某个topic进行扩分区的操作&#xff0c;想必大家肯定都使用过。尤其是集群进行扩容时&#xff0c;对流量较大的topic进行扩分区操作。一般而言&#xff0c;期望的效果是&#xff1a;新扩的分…

AI在医学领域:HYDEN一种针对医学图像和报告的跨模态表示学习方法

近年来&#xff0c;跨模态文本-图像表示学习在诸多领域取得了显著的突破&#xff0c;尤其是在零样本学习和图像-文本检索等任务上。这一成果的取得很大程度上归功于大量弱监督的图像-文本配对数据的利用&#xff0c;这些数据有效地增强了视觉-语言表示学习的能力。在医学成像领…

如何保证每次生成的都同一张人脸?AI绘画Stable Diffusion的Reference only插件人物一致性教程

Ai绘画有一个很现实的问题&#xff0c;要保证每次画出的都是同一个人物的话&#xff0c;很费劲。 Midjourney就不必说了&#xff0c;人物的高度一致性一直得不到很好的解决。而在Stable Diffusion&#xff08;SD&#xff09;中&#xff0c;常用办法是通过同一个Seed值&#xf…

Linux宝塔面板使用教程 - Centos/Alibaba Cloud Linux,解放命令实现可视化

使用前注意事项&#xff1a;为了您的正常使用&#xff0c;请确保使用全新或纯净的系统安装宝塔面板&#xff0c;不支持已部署项目/环境的系统安装 1.安装命令 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh &&…

Godot《躲避小兵》实战之创建游戏主场景

游戏主场景 现在是时候将我们所做的一切整合到一个可玩的游戏场景中了。 创建新场景并添加一个 Node节点&#xff0c;命名为 Main。&#xff08;我们之所以使用 Node 而不是 Node2D&#xff0c;是因为这个节点会作为处理游戏逻辑的容器使用。本身是不需要 2D 功能的。&#x…

ZooKeeper 的3种部署模式

ZooKeeper 的3种部署模式 1. 单机模式&#xff08;Standalone Mode&#xff09;2. 伪集群模式&#xff08;Pseudo-Cluster Mode&#xff09;3. 集群模式&#xff08;Cluster Mode&#xff09; &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496;…

[000-01-011].第2节:持久层方案的对比

我的后端学习大纲 MyBatis学习大纲 1.持久层解决方案&#xff1a; 1.1.面试1&#xff1a;请说一说持久层解决方案有哪些&#xff1f;&#xff1f;&#xff1f; 1.jdbc JDBC为访问不同的数据库提供了一种统一的途径&#xff0c;为开发者屏蔽了一些细节问题。Java程序员使用JDB…

Vodafone 推出了与 Wi-Fi 竞争的基于树莓派私人5G技术

随着全球5G网络的逐步推出&#xff0c;在其过程中遇到了可预见的起起伏伏&#xff0c;并且蜂窝技术也开始进入另一个无线技术 Wi-Fi &#xff0c;并且已经占据的市场。私有5G网络&#xff08;即个人或公司建立自己的全设施蜂窝网络&#xff09;如今正在寻找曾经属于Wi-Fi的唯一…

Unity低延迟播放RTSP视频流

Unity播放RTSP视频流这个功能在好几个项目中用到&#xff0c;虽然有一些现成的插件&#xff08;VLC for unity、UMP&#xff09;可以使用&#xff0c;但是延迟高&#xff08;300毫秒以上&#xff09;的问题一直没法解决。 最近终于下定决心来解决这个问题&#xff0c;经过几天…

基于 Jenkins、Gitlab、Harbor、Helm 和 Kubernetes 的 CI/CD

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

【微服务部署】Linux部署微服务启动报ORA-01005

问题背景&#xff1a; Linux机器部署springboot微服务&#xff0c;部署完成后发现无法启动&#xff0c;后台报ORA-01005错误。 解决方案&#xff1a; 1.检查当前服务器是否已安装oracle客户端 命令行执行sqlplus username/passwd实例名&#xff0c;如果执行成功&#xff0c;说…

【Canvas与艺术】十边曲线形光阑

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>十边曲线型光阑</title><style type"text/css"&g…

机器学习-识别手写数字

机器学习可以首先构建一个神经网络&#xff0c;用于识别手写数字。通过训练数据&#xff0c;优化神经网络的参数。再利用测试数据来测试训练完成后的神经网络的准确度。本次需要下载的库有tensorflow和matplotlib&#xff0c;keras和mnist数据集一般都被集成在tensorflow中了。…

C/C++语言基础--指针三大专题详解3,完结篇(包括指针做函数参数,函数指针,回调函数,左右法则分析复杂指针等)

本专栏目的 更新C/C的基础语法&#xff0c;包括C的一些新特性 前言 指针是C/C的灵魂&#xff0c;和内存地址相关联&#xff0c;运行的时候速度快&#xff0c;但是同时也有很多细节和规范要注意的&#xff0c;毕竟内存泄漏是很恐怖的指针打算分三篇文章进行讲解&#xff0c;本…

LabVIEW多显示器环境下主显示器识别与管理

该程序使用 LabVIEW 图形化编程语言&#xff0c;涉及多显示器环境中主显示器的识别与信息提取。图像显示了两个不同的方法来获取主显示器的信息。 第一部分&#xff1a;方法一——基于显示器位置的主显示器识别 1. 当前监视器识别&#xff1a; 使用“FP.Monitor”属性节点获取…

在AES加密中,设主密钥为“2B 7E 15 16 28 AE D2 A6 AB F7 15 88 09 CF 4F 3C”,试计算迭代第1轮使用的轮密钥。

题解: 1.分析: 第一轮使用的轮密钥是W[4]、W[5]、W[6]、W[7] w[i](4≤i≤43)求法: (1)i不为4的倍数 w[i] = w[i-1] ⊕w[i-4] (2)为4的倍数 w[i]=SubWord(RotWord(w[i-1]))⊕w[i-4]⊕Rcon[i/4] 解释: ①RotWord:将w[i-1]的4个字节循环上移一个字节 ②SubWo…

JVM的类是如何运行的

本文就是讲解 如何将.class文件转换为机器码

U盘中毒文件被隐藏怎么恢复文件?

很多用户都曾经遇到过U盘文件被病毒隐藏的问题&#xff0c;U盘作为拷贝、存储文件最主要的移动存储设备&#xff0c;里面经常存储了重要的文件&#xff0c;如果文件被隐藏了会给用户带来很多麻烦。那么U盘文件被病毒隐藏&#xff0c;应该怎么解决呢&#xff1f;本文列举了有效的…