基础算法篇(5)(蓝桥杯常考点)—动态规划(C/C++)

文章目录

  • 动态规划
    • 前言
    • 线性dp
    • 路径类dp
    • 经典线性dp
    • 背包问题分类
    • 01背包问题
    • 完全背包问题
    • 多重背包
    • 分组背包问题
    • 混合背包问题
    • 多维费用的背包问题
    • 区间dp

动态规划

前言

在竞赛中,如果遇到动态规划的题目,只要不是经典题型,那么大概率就是以压轴题的形式出现

用动态规划解决问题的步骤:(递推形式)

1.定义状态表示:

根据经验+需要的意义,赋予dp数组相应的含义

(主要还是看需要记什么)

2.推导状态转移方程:

在dp表中分析,当前格子如何通过其余格子推导出来的

3.初始化:

将显而易见的以及边界情况下的位置填上值,来让后续填表的结果是正确的

4.确定填表顺序:

根据状态转移方程,确定按照什么顺序来填表

5.找出最终结果:

在表中找出需要的最终结果

洛谷 P10250 [GESP样题 六级] 下楼梯
洛谷 P1216 [USACO1.5] [IOI1994]数字三⻆形 Number Triangles

动态规划常要空间优化:
即把不用了的值给不要了
但是背包问题如果不能用1个数组优化,而要多个数组的话,那就不空间优化了,否则可能会超时
常见的优化方法:
方法一:一维转几个数
例题:洛谷   P10250 [GESP样题 六级] 下楼梯方法二:二维转一维
1.是否需要修改遍历顺序
2.删掉一维即可
例题:洛谷  P1216 [USACO1.5] [IOI1994]数字三⻆形 Number Triangles

洛谷 P1115 最⼤⼦段和
洛谷 P1541 [NOIP2010 提⾼组] 乌⻳棋

一些技巧:
1.状态表示:
a.研究子数组或子序列问题时,从某个位置结尾来定义状态表示 例:洛谷 P1115 最⼤⼦段和
b.优化问题:有一维可以由其他维的数据推出的话,可以不要这一维(不是指那个空间优化方法)例题:洛谷  P1541 [NOIP2010 提⾼组] 乌⻳棋2.状态转移方程:
a.求方案数一般是相加
b.常从最后一步开始分析去推导状态转移方程3.初始化:
在求方案数时,一般将第一个位置初始化为1,其他位置为0

线性dp

特点:状态转移只依赖于前一个或前几个状态;状态之间的关系是线性的

路径类dp

洛谷 P1004 [NOIP2000 提⾼组] ⽅格取数

走两次的得到的值之和最大问题:
(两次的规则要一样,走到不同位置的得到的值不一样,且每位置的值只能得一次)
例题:洛谷  P1004 [NOIP2000 提⾼组] ⽅格取数
在状态表示时:两者如果是同时出发的(非同步则要改一点),其横纵坐标之和会是一个定值
一般表示为f[st][i1][i2]:
意思是:第一条路在[i1,st-i1],第二条路在[i2,st-i2]时,两者的路径(取数)之和最大

经典线性dp

经典线性dp问题有两个:最长上升子序列和最长公共子序列

这两道题的解题思路,定义状态表示方式和推导状态转移方程的技巧常被用到其他题目中去

洛谷 B3637 最⻓上升⼦序列
洛谷 P1091 [NOIP2004 提⾼组] 合唱队形

最长上升子序列(数据范围小时用此)
时间复杂度是O(n平方)
链接:洛谷  B3637 最⻓上升⼦序列
要理解最长上升子序列是什么意思!!!
1.状态表示:
dp[i]表示:以i位置为结尾的所有子序列中,最长递增子序列的长度
2.状态转移方程:
根据子序列的构成方式进行分类讨论:第一种:子序列长度为1:此时的dp[i] = 1;
第二种: 子序列的长度大于1:设j为前面某一个数的下标
只要a[j]<a[i],i位置元素跟在j元素后面就可以形成递增序列
其dp[i] = max(dp[j]+1p,dp[i])
3.初始化:
每次填表的时候,先把这个位置的数改成最小的域值即可主要部分的代码展示:
int ret = 0;
for(int i=1;i<=n;i++)
{ 
dp[i]=1;
for(int j=1;j<i;j++){if(a[j]<a[i])dp[i] = max(dp[i],dp[j]+1); }ret = max(ret,dp[i])
}应用: 洛谷  P1091 [NOIP2004 提⾼组] 合唱队形

牛客网 【模板】最⻓上升⼦序列

最长上升子序列(数据范围大时用此)
时间复杂度时O(n*logn)
链接:牛客网 【模板】最⻓上升⼦序列
优化动态规划:
1.发现在考虑最长递增子序列长度时,只用关心现在长度和序列最后一个元素
因此仅需统计长度为x的所有递增序列中最后一个元素的最小值(创建数组去统计)
2.在统计过程中发现:
数组中的数呈现递增趋势,因为可以使用二分来查找插入位置
主要部分的代码展示:
for(int i =1;i<=n;i++)
{//处理边界情况if(len ==0||a[i]>f[len]) f[++len]=a[i];
else{//二分插入位置int l = 1,r = len;while(l<r){int mid = (l+r)/2;if(f[mid]>=a[i]) r = mid;else l =mid+1;}f[l] = a[i]} }

牛客网 ⽜可乐和最⻓公共⼦序列
洛谷 P2758 编辑距离

牛可乐和最长公共子序列
链接:牛客网  ⽜可乐和最⻓公共⼦序列
1.状态表示:
dp[i][j]表示:
s1的[1,i]区间以及s2的[1,j]区间内的所有的子序列中,最长公共子序列的长度2.状态转移方程:
对于dp[i][j],我们可以根据s1[i]与s2[j]的字符分情况讨论:
第一种:两个字符相同 dp[i][j] = dp[i-1][j-1]+1
第二种:两个字符不同 有以下三种策略
a.去s1的[1,i-1]以及s2的[1,j]区间内找:此时最大长度为dp[i-1][j]
b.去s1的[1,i]以及s2的[1,j-1]区间内找:此时最大长度为dp[i][j-1]
c.去s1的[1,i-1]以及s2的[1,j-1]区间内找:此时最大长度为dp[i-1][j-1]
(发现c包含在a和b情况里)
然后要a,b中的最大值即可代码展示:
for(int i =1;i<=n;i++)
{for(int j = 1;j<=m;j++){if(s[i-1] == t[j-1])f[i][j] = f[i-1][j-1]+1;else f[i][j] = max(f[i-1],f[i][j-1])}}应用:洛谷  P2758 编辑距离

背包问题分类

01背包问题:没中物品只能选或不选(选0次或1次)

完全背包问题:每种物品可以选择无限次

多重背包问题:每种物品有数量限制

分治背包问题:物品被分为若干组,每组只能选一个物品

混合背包:以上四种背包问题混在一起

多维费用的背包问题:限定条件不止有体积,还会有其他因素(比如重量)

背包问题的三种限定情况:
1.体积不超过j->小于等于j->j>=v[i]
2.体积正好为j->恰好等于j->要判断f表中某些状态是否合法
3.体积至少为j->大于等于j->j<v[i]也是合法的,映射到0位置即可背包问题在求方案数时,要把不选的情况单独写出,然后从只选一个开始,不然套模板可能会错
例:洛谷  P1077 [NOIP2012 普及组] 摆花

洛谷 P1077 [NOIP2012 普及组] 摆花

01背包问题

牛客网 【模板】01背包
洛谷 P2946 [USACO09MAR] Cow Frisbee Team S

01背包中的最大价值问题:
模板题:牛客网 【模板】01背包
v[i]表示第i个的体积   w[i]表示第i个的价值
第一问:求这个背包至多能装多大价值的物品1.状态表示:
dp[i][j]表示:从前i个物品中挑选,总体积不超过j,所有的选法中,能挑选出来的最大价值
那么dp[n][v]就是我们要的结果
2.状态转移方程:
dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i])
3.初始化:无
4.填表顺序:从上往下(二维一般都是从上往下)  从右往左代码表现:
for(int i = 1;i<=n;i++)
{ for(int j=0;j<=m;j++){f[i][j] = f[i-1][j];if(j>=v[i])f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);}
}
空间优化版:(熟练了之后,直接写此)for(int i = 1;i<=n;i++)
{ for(int j=m;j>=v[i];j--)//01背包空间优化要修改遍历顺序{f[j] = max(f[j],f[j-v[i]]+w[i]);}
}第二问:
若背包恰好装满,求至少能装多大价值
仅需要在第一问基础上修改一下初始化以及最终结果即可
1.初始化
把所有位置先设置成-0x3f3f3f3f;然后把dp[0][0]修改成0
2.最终结果
要多一步判断最后一个位置是不是小于0代码展现:
memset(f,-0x3f,sizeof f);//多了这个
for(int i = 1;i<=n;i++)
{ for(int j=0;j<=m;j++){f[i][j] = f[i-1][j];if(j>=v[i])f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);}
}
if(f[n][m]<0)cout<<0<<endl;//多了这个
else cout << f[n][m]<<endl;//多了这个
空间优化版:(熟练了之后,直接写此)
memset(f,-0x3f,sizeof f);for(int i = 1;i<=n;i++)
{ for(int j=m;j>=v[i];j--)//01背包空间优化要修改遍历顺序{f[j] = max(f[j],f[j-v[i]]+w[i]);}
}
if(f[m]<0)cout<<0<<endl;
else cout << f[m]<<endl;注意:有些题可能不能用这种空间优化,因为要用到之前的数据的多少不同了
例题:洛谷  P2946 [USACO09MAR] Cow Frisbee Team S
(这题还要注意的是状态表示不能搞能力值总和为j,要搞总和模之后为j,不然空间时间都易超)

洛谷 P1164 ⼩A点菜

01背包中的方案数问题:
题目链接:洛谷  P1164 ⼩A点菜
1.状态表示:
dp[i][j]表示:从前i个菜中挑选,总价钱恰好等于j,此时的总方案数
2.针对于a[i]选或不选,分两种情况讨论:
得:dp[i][j] = d[i-1][j]+d[i-1][j-a[i]]
注意第二个状态可能不存在,要注意判断一下j>=a[i]
3.初始化:
dp[0][0] = 1

完全背包问题

牛客网 【模板】完全背包

模板题:牛客网 【模板】完全背包
第一问:求这个背包至多能装多大价值的物品
1.状态表示:和01背包一样
2.状态转移方程:
dp[i][j] = max(dp[i-1][j],dp[i][j-v[i]]+w[i])
3.初始化:
从第二行开始存,第一行全初始化为0
4.没有空间优化时,是从上往下,从左往右第二问:若背包恰好装满,求至多能装多大价值的物品
改法跟01背包那里完全相同与01背包的不同点:在空间优化时,完全背包的遍历顺序还是从左往右

多重背包

牛客网 多重背包

例题: 牛客网  多重背包
小tip:不是所有的多重背包问题都能用二进制优化,而且优化版本的代码很长如果时间复杂度允许的情况下,能不优化就不优化
解法一:
1.状态表示:
dp[i][j]表示:
从前i个物品中挑选,总重量不超过j的情况下,最大的价值2.状态转移方程:
这里不能用完全背包的方式(不是指那个空间优化)去优化
只能硬分x[i]+1种情况(选0个到选x[i]个)
选x[i]个:价值为dp[i-1][j-x[i]*w[i]]+x[i]*v[i] 3.初始化:
全部初始化为04.填表顺序:
从上往下,从左往右
空间优化之后则是从右往左代码展现:
for(int i =1;i<=n;i++)for(int j= m;j>=0;j--)for(int k = 0;k<=x[i]&&k*w[i]<=j;k++)f[j] = max(f[j],f[j-k*w[i]]+k*v[i])解法二:转化为01背包问题
优化方式:用二进制将同种的x[i]个物品分组
(如果是求方案数的话,是不能用二进制去优化的,会多算几种)
把这x[i]个物品拆成一些二进制数再加上多出来的数此题的有100种不同物品的话
如果同种的物品最多能分成5份,则数组的N要取(100+10)*5//+10纯属个人习惯

洛谷 P1077 [NOIP2012 普及组] 摆花

多重背包的方案数问题:
例题:洛谷  P1077 [NOIP2012 普及组] 摆花
也就状态转移方程和初始化改了一下

分组背包问题

洛谷 P1757 通天之分组背包

例题:洛谷  P1757 通天之分组背包
1.状态表示:
dp[i][j]表示从前i组中挑选物品,总重量不超过j的情况下,最大的价值2.状态转移方程:
根据第i组选什么物品,可以分若干情况讨论
这个在空间优化时,第二维也要从右到左

混合背包问题

洛谷 P1833 樱花

例题:洛谷 P1833 樱花
这个混合背包的话,分情况讨论是哪种背包就是
注意的点是:多重背包和01背包的代码具有可合并性

多维费用的背包问题

洛谷 P1910 L 国的战⽃之间谍

例题:洛谷  P1910 L 国的战⽃之间谍
这无非就是多加几维就行
eg:
状态表示:
dp[i][j][k]表示:
从前i个人中挑选,伪装能力不超过j,总工资不超过k,此时能获取到的最多资料总数
eg:像这种获取到的最多资料总数,能砍到的最多的树木这种一般不为限制条件,一般是所求的值
在空间优化时,也只能优化掉第一维(从前i个人中挑选--这个一般放第一维)
空间优化后,除了第一维的遍历顺序可能都需要发生变化

区间dp

区间dp是用区间的左右端点来描述状态,通过小区间的解来推导出大区间的解

核心思想:将大区间划分为小区间,其状态转移方程通常依赖于区间的划分点

常见的划分点的方式有两个:

1.基于区间的左右端点,分情况讨论

2.基于区间上的某一个点,划分成左右区间讨论

应用:在序列中只关心左右两端,大概率用区间dp

洛谷 P1435 [IOI2000] 回⽂字串

例题:洛谷  P1435 [IOI2000] 回⽂字串
1.状态表示:
dp[i][j]表示:
字符串[i,j]区间,变成回文串的最小插入次数
那么,dp[1][n]就是我们要的结果2.状态转移方程:
根据区间的左右端点,分情况讨论对于区间dp的填表顺序,一般用的是:
第一维循环:从小到大枚举区间长度len;第二维循环:枚举区间左端点i,然后计算出区间右端点j
j = i+len-1 
这个len有时从1开始,有时从2开始,看题
eg:
for(int len = 1;len<=n;len++)for(int i = 1; i+len-1<=n;i++)

洛谷 P2858 [USACO06FEB] Treats for the Cows G/S
洛谷 P3146 [USACO16OPEN] 248 G

关于这里的状态转移方程:
1.如果划分点是基于区间的左右端点,分情况讨论
eg: 洛谷  P2858 [USACO06FEB] Treats for the Cows G/S先拿左边,然后去[i + 1, j] 区间获得最多的钱,
即a[i] × (n − len + 1) + dp[i + 1][j] 先拿右边,然后去[i,j-1]区间获得最多的钱
即a[j]*(n-len+1)+de[i][j-1]2.如果划分点是基于区间上的某一个点,划分成左右区间讨论
eg: 洛谷    P3146 [USACO16OPEN] 248 G根据最后一次合并的情况,可以把区间分成[i,k][k+1,j](划分点是k)

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

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

相关文章

obsidian写文章的图床设置方法

目标 要达成的需求&#xff1a; 复制到obsidian的图片&#xff0c;自动上传到Picgo配置的图床。可以自定义大小。可以一键下载当前文章的图片到本地。 obsidian配置图床 安装并配置插件 image auto upload plugin&#xff0c;配置信息如下图。 滚轮alt自定义大小 安装并…

QPaintDevice绘图设备

1.QPixmap 对不同平台做了显示的优化&#xff0c;可以将画的图保存到磁盘上 头文件&#xff1a; #include"QPixmap" #include"QPainter" 1.1QPixmap画图 代码&#xff1a; //Pixmap绘图设备QPixmap pix(300,300);//声明画家QPainter painter(&pix…

数据结构有哪些类型(对于数据结构的简述)

在学习计算机时&#xff0c;数据结构是不可忽视的一点&#xff0c;从考研时的408课程&#xff0c;再到工作中编写软件&#xff0c;网站&#xff0c;要想在计算机领域站住脚跟&#xff0c;数据结构是必备的 在这里&#xff0c;我对于数据结构进行了汇总&#xff0c;并简要描述&…

L2TP实验(无图后补)

拓扑图 一、搭建拓扑并配置基础 IP 地址 设备选型与拓扑搭建&#xff1a;在 eNSP 中&#xff0c;拖入所需设备&#xff0c;包括 LAC&#xff08;L2TP Access Concentrator&#xff0c;L2TP 接入集中器 &#xff09;、LNS&#xff08;L2TP Network Server&#xff0c;L2TP 网络服…

【C#】CAN通信的使用

在C#中实现CAN通信通常需要借助第三方库或硬件设备的驱动程序&#xff0c;因为C#本身并没有直接内置支持CAN通信的功能。以下是一个关于如何使用C#实现CAN通信的基本指南&#xff0c;包括所需的步骤和常用工具。 1. 硬件准备 要进行CAN通信&#xff0c;首先需要一个支持CAN协…

02_C++入门案例习题while循环练习案例:猜数字

案例描述&#xff1a;系统随机生成一个1到100之间的数字&#xff0c;玩家进行猜测&#xff0c;如果猜错&#xff0c;提示玩家数字过大或过小&#xff0c;如果猜对恭喜玩家胜利&#xff0c;并且退出游戏。 需要引入随机数种子 #include <cstdlib> #include <ctime>…

深入理解哈希冲突:原理、解决方案及 Java 实践

概述&#xff1a;在计算机科学领域&#xff0c;哈希表是一种非常重要的数据结构&#xff0c;它通过哈希函数将键映射到存储桶中&#xff0c;从而实现快速的数据查找、插入和删除操作。然而&#xff0c;哈希表在实际应用中会面临 哈希冲突的问题。本文将深入探讨哈希冲突的原理、…

opencv(C++)处理图像颜色

文章目录 介绍使用策略设计模式比较颜色实现方案计算两个颜色向量之间的距离1. 简单方法&#xff1a;曼哈顿距离计算&#xff08;Manhattan Distance&#xff09;2.使用 OpenCV 的 cv::norm 函数3.使用 OpenCV 的 cv::absdiff 函数错误示例 使用 OpenCV 函数实现颜色检测实现方…

DOM解析XML:Java程序员的“乐高积木式“数据搭建

各位代码建筑师们&#xff01;今天我们要玩一个把XML变成内存乐高城堡的游戏——DOM解析&#xff01;和SAX那种"边看监控边破案"的刺激不同&#xff0c;DOM就像把整个乐高说明书一次性倒进大脑&#xff0c;然后慢慢拼装&#xff08;内存&#xff1a;你不要过来啊&…

Apache Nifi安装与尝试

Apache NIFI中文文档 地址&#xff1a;https://nifichina.github.io/ 下载安装配置 1、环境准备 Nifi的运行需要依赖于java环境&#xff0c;所以本机上需要安装java环境&#xff0c;并配置环境变量。 1.1查看本机是否已经存在java环境 请先执行以下命令找出系统中真实可用…

我可能用到的网站和软件

我可能用到的网站和软件 程序员交流的网站代码管理工具前端组件库前端框架在线工具人工智能问答工具学习的网站Windows系统电脑的常用工具 程序员交流的网站 csdn博客博客园 - 开发者的网上家园InfoQ - 软件开发及相关领域-极客邦掘金 (juejin.cn) 代码管理工具 GitHub 有时…

使用SSH解决在IDEA中Push出现403的问题

错误截图&#xff1a; 控制台日志&#xff1a; 12:15:34.649: [xxx] git -c core.quotepathfalse -c log.showSignaturefalse push --progress --porcelain master refs/heads/master:master fatal: unable to access https://github.com/xxx.git/: The requested URL return…

JavaScript异常机制与严格模式

目录 JavaScript 异常机制 1. 基本语法&#xff1a;try...catch...finally 2. 抛出异常&#xff1a;throw 3. 错误对象属性 4. 同步代码的异常处理 5. 异步代码的异常处理 5.1 回调函数 5.2 Promise 5.3 全局未捕获的 Promise 错误 6. 全局错误处理 7. 自定义错误与…

中厂算法岗面试总结

时间&#xff1a;2025.4.10 地点&#xff1a;上市的电子有限公司 面试流程&#xff1a; 1.由负责人讲解公司文化 2&#xff0c;由技术人员讲解公司的技术岗位&#xff0c;还有成果 3.带领参观各个工作位置&#xff0c;还有场所 4.中午吃饭 5.面试题&#xff0c;闭卷考试…

vue+flask图书知识图谱推荐系统

文章结尾部分有CSDN官方提供的学长 联系方式名片 文章结尾部分有CSDN官方提供的学长 联系方式名片 关注B站&#xff0c;有好处&#xff01; 编号: F025 架构: vueflaskneo4jmysql 亮点&#xff1a;协同过滤推荐算法知识图谱可视化 支持爬取图书数据&#xff0c;数据超过万条&am…

MySQL NDB Cluster详解

MySQL NDB Cluster&#xff08;MNC&#xff09; 是MySQL提供的一种分布式数据库解决方案&#xff0c;旨在提供高可用性、高性能的数据库服务。它通过 NDB&#xff08;Network DataBase&#xff09; 存储引擎实现了高可用性和分布式存储&#xff0c;在NDB中&#xff0c;数据通过…

解决华硕主板Z890m下载ubuntu20.04后没有以太网问题

问题描述&#xff1a; 华硕主板Z890m下载双系统ubuntu20.04后&#xff0c;发现ubuntu不能打开以太网。 问题原因&#xff1a; 华硕主板的网卡驱动是r8125,而ubuntu20.04的驱动版本是r8169&#xff0c;所以是网卡驱动不匹配造成 解决方案 开机界面按下F2进入BOIS模式&#…

JS里对于集合的简单介绍

JS的集合 前言一、集合二、基本使用1. 创建集合2. 添加元素3. 删除元素4. 检查元素5. 清空集合6. 集合的大小 三、扩展使用1. 遍历集合2. 从数组创建集合3. 集合的应用场景 四、总结 前言 JS里对于集合的简单介绍 同数学的集合&#xff0c;有无序性、唯一性 注意&#xff1a;…

pytorch 反向传播

文章目录 概念计算图自动求导的两种模式 自动求导-代码标量的反向传播非标量变量的反向传播将某些计算移动到计算图之外 概念 核心&#xff1a;链式法则 深度学习框架通过自动计算导数(自动微分)来加快求导。 实践中&#xff0c;根据涉及号的模型&#xff0c;系统会构建一个计…

Kotlin日常使用函数记录

文章目录 前言字符串集合1.两个集合的差集2.集合转数组2.1.集合转基本数据类型数组2.2.集合转对象数组 Map1.合并Map1.1.使用 操作符1.2.使用 操作符1.3.使用 putAll 方法1.4.使用 merge 函数 前言 记录一些kotlin开发中&#xff0c;日常使用的函数和方式之类的&#xff0c;…