当前位置: 首页 > news >正文

20250907 线性DP总结

引子

让我们先回顾一下动态规划的基础知识。动态规划问题具有三个核心特征:

  1. 最优子结构:这是动态规划中的"状态"概念,通过已知状态推导出未知状态,最终得到问题的解
  2. 重叠子问题:在状态转移过程中会出现大量重复计算,通常使用dp数组来存储这些状态
  3. 无后效性:已确定的状态不会受到后续计算的影响

动态规划的解题步骤可以归纳为:

  • 将原问题分解为若干子问题(即定义状态)
  • 建立状态之间的转移关系(推导状态转移方程)
  • 按顺序求解所有状态,最终得到问题的解。

线性DP

进入正题,线性DP指的是什么?顾名思义,就是线性相关的动态规划。这不废话吗!?但不讲怎么过审核……

咳咳,如果题目中有序列、数组,那么动态规划的状态就是一维的,也就是线性;如果题目中有网格、棋盘,那么动态规划的状态就是二维的。

例题

A - 最大差值

HKE最近对序列研究产生了浓厚兴趣,他在研究过程中发现了一个有趣的问题:

给定一个长度为n的序列A₁, A₂, …, Aₙ,需要找到两个下标i,j(1≤i<j≤n),使得Aⱼ - Aᵢ的值达到最大。

现在给定这个序列,请计算并返回Aⱼ - Aᵢ的最大值。

首先不要想着找到最大值和最小值然后相减就行了,iii还得小于jjj啊,别被坑了……

这题需要两个数组,mnmnmnmxmxmxmn[i]mn[i]mn[i]代表前iii个值的最小值,mx[i]mx[i]mx[i]代表后iii个值的最大值,
那么答案就是对于每一个i(1≤i≤n−1)mx[i+1]−mn[i]i(1\leq i\leq n-1)mx [ i + 1 ] -mn[i]i(1in1)mx[i+1]mn[i]的最大值。

再提一句,数据很坑,答案有可能是负数。

时间复杂度O(n)

#include<bits/stdc++.h>
using namespace std;
long long mn[1000005],mx[1000005];//一定要开long long
int main(){int n;cin>>n;for(int i=1;i<=n;i++){cin>>mn[i];mx[i]=mn[i];}for(int i=2;i<=n;i++){//前i个的最小值mn[i]=min(mn[i],mn[i-1]);}for(int i=n-1;i>=1;i--){//后i个的最大值mx[i]=max(mx[i],mx[i+1]);}long long ans=LONG_LONG_MIN;//注意是long long minfor(int i=1;i<n;i++){ans=max(ans,mx[i+1]-mn[i]);}cout<<ans;return 0;
}

B - Frog 1

NNN块石头,编号为111NNN。每块石头i(1≤i≤N)i(1≤i≤N)i1iN的高度为hih_ihi

一只青蛙最初位于第111块石头上,它将通过以下跳跃方式到达第NNN块石头:

  • 当青蛙位于第iii块石头时,可以选择跳到第i+1i+1i+1i+2i+2i+2块石头
  • 每次跳跃的代价为∣hi−hj∣|h_i - h_j|hihj,其中j是目标石头的编号

要求计算青蛙到达第NNN块石头的最小总代价。

妥妥的DP模板啊!我们把dp[i]dp[i]dp[i]定义为到iii下标最小的代价,最后的答案就是dp[n]dp[n]dp[n]

时间复杂度O(n)

#include<bits/stdc++.h>
using namespace std;
int a[100005],dp[100005];
int main(){memset(dp,0x3f,sizeof dp);//首先把 DP设为无穷大int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i];}dp[1]=0;//从 1到 1代价为 0for(int i=1;i<=n;i++){//扩散型 DPif(i+1<=n){//如果跳一格没有越界dp[i+1]=min(dp[i+1],dp[i]+abs(a[i]-a[i+1]));//用目前的代价加上到目标石头的距离更新目标石头的最小代价}if(i+2<=n){//如果跳两格没有越界dp[i+2]=min(dp[i+2],dp[i]+abs(a[i]-a[i+2]));//用目前的代价加上到目标石头的距离更新目标石头的最小代价}}cout<<dp[n];//输出答案return 0;
}

C - Frog 2

有编号为1到N的N块石头排列成一排。

对于每块石头i(1≤i≤N)i(1≤i≤N)i1iN,其高度记为hih_ihi

一只青蛙最初站在第111块石头上,它需要通过一系列跳跃到达第NNN块石头。每次跳跃时:

若青蛙当前位于第iii块石头,它可以跳到第i+1i+1i+1到第i+Ki+Ki+K块石头中的任意一块(不超过NNN)。每次跳跃的代价为∣hi−hj∣|h_i - h_j|hihj,其中jjj是目标石头的编号。

我们的目标是计算青蛙到达第NNN块石头所需的最小总代价。

说白了还是B题,不做赘述了才怪,细节在代码里。

时间复杂度O(nk)

#include<bits/stdc++.h>
using namespace std;
int a[100005];
int dp[100005];
int main(){memset(dp,0x3f,sizeof dp);int n,k;cin>>n>>k;for(int i=1;i<=n;i++){cin>>a[i];}dp[1]=0;// 1到 1的代价为 0for(int i=1;i<=n;i++){//还是扩散型 DPfor(int j=1;j<=k;j++){if(i+j<=n){//如果跳k格没有越界dp[i+j]=min(dp[i+j],dp[i]+abs(a[i]-a[i+j]));//用目前的代价加上到目标石头的距离更新目标石头的最小代价}}}cout<<dp[n];//代码基本一致return 0;
}

D - Vacation

太郎的暑假将于明天开始,他决定提前规划好假期安排。

假期共有N天。对于每一天i(1≤i≤N),太郎可以选择以下活动之一:

A:海边游泳,获得aia_iai点快乐值
B:山中捉虫,获得bib_ibi点快乐值
C:在家写作业,获得cic_ici点快乐值

需要注意的是,太郎不能连续两天选择相同活动,否则会感到无聊。

请计算太郎在假期中能获得的最大快乐值总和。

严重怀疑cic_ici< 000……

事实证明,可以一边输入一边做处理,状态怎么设计呢?其实应该很容易想到,dp[i][1]dp[i][1]dp[i][1]代表第iii天在海里游泳可得到的最多快乐值,dp[i][2]dp[i][2]dp[i][2]代表第iii天在在山上捉虫子可得到的最多快乐值,dp[i][3]dp[i][3]dp[i][3]代表第iii天在在家做作业可得到的最多快乐值,于是答案就是max(dp[n][1],dp[n][2],dp[n][3])max(dp[n][1],dp[n][2],dp[n][3])max(dp[n][1],dp[n][2],dp[n][3])

时间复杂度O(n)

#include<bits/stdc++.h>
using namespace std;
int dp[100005][5];
int main(){int n;cin>>n;for(int i=1;i<=n;i++){int a,b,c;cin>>a>>b>>c;if(i==1){//如果是第一天,就直接赋值dp[i][1]=a;dp[i][2]=b;dp[i][3]=c;}else{dp[i][1]=max(dp[i-1][2],dp[i-1][3])+a;//前一天B、C活动获得的快乐值的最大值加上今天在海里游泳的快乐值dp[i][2]=max(dp[i-1][1],dp[i-1][3])+b;//前一天A、C活动获得的快乐值的最大值加上今天在山上捉虫的快乐值dp[i][3]=max(dp[i-1][2],dp[i-1][1])+c;//前一天A、B活动获得的快乐值的最大值加上今天在家做作业的快乐值}}cout<<max(dp[n][1],max(dp[n][2],dp[n][3]));//最终答案return 0;
}

文章转载自:

http://NRsQsQ2s.kscwt.cn
http://391IyDVR.kscwt.cn
http://0jPxBv0M.kscwt.cn
http://AsZzBOh0.kscwt.cn
http://LyssKCbC.kscwt.cn
http://98XlMQCl.kscwt.cn
http://uZzMa128.kscwt.cn
http://jhRIufY4.kscwt.cn
http://CxMkpmYH.kscwt.cn
http://g3B2R60O.kscwt.cn
http://va0BZRC6.kscwt.cn
http://UQPiyunF.kscwt.cn
http://24DfTuBP.kscwt.cn
http://6z8307mB.kscwt.cn
http://MBcQgdSk.kscwt.cn
http://2IyVGDK4.kscwt.cn
http://To53Cy3c.kscwt.cn
http://jmkjdZ8I.kscwt.cn
http://bIZXkRZD.kscwt.cn
http://CbAC88F3.kscwt.cn
http://c8YIemqR.kscwt.cn
http://4lbSt2sc.kscwt.cn
http://nAQa5g3a.kscwt.cn
http://CfjO8ZFj.kscwt.cn
http://Sfek8SlY.kscwt.cn
http://MRwuV90N.kscwt.cn
http://rgKJcsbt.kscwt.cn
http://HBvnFR7S.kscwt.cn
http://fmShFple.kscwt.cn
http://KK1ZI2ya.kscwt.cn
http://www.dtcms.com/a/371782.html

相关文章:

  • 实战演练:通过API获取商品详情并展示
  • 新建Jakarta EE项目,Maven Archetype 选项无法加载出内容该怎么办?
  • 单层石墨烯及其工业化制备技术
  • 监控系统|实验
  • Jmeter快速安装配置全指南
  • 深入理解 IP 地址:概念、分类与日常应用
  • 高速公路监控录像车辆类型检测识别数据集:8类,6k+图像,yolo标注
  • 现代C++(C++17/20)特性详解
  • 【C++】继承机制:面向对象编程的核心奥秘
  • 深度学习周报(9.1~9.7)
  • Spring 日志文件
  • 【HARP 第二期】HARP 的数据组织“约定”规范
  • 钾元素:从基础认知到多元应用与前沿探索
  • 如何短时间内精准定位指标异动根源
  • Geogebra 绘制 电磁波反射折射+斯涅尔定律+半波损失
  • Mia for Gmail for Mac 邮件管理软件
  • EXCEL VBA 清空Excel工作表(Sheet)的方法
  • kafka如何保证消息的顺序性
  • Python快速入门专业版(十):字符串特殊操作:去除空格、判断类型与编码转换
  • 【数据分析】微生物组数据的批次校正与分析
  • 技术前瞻:衡石Data Agent在多模态AI与复杂数据源下的扩展与挑战
  • 如何通过 Activepieces 实现智能工作流自动化
  • Knex 和 Schema 是什么?
  • vector类(一)
  • OpenLayers常用控件 -- 章节八:地图动画控件教程
  • 在 CI/CD 管道中集成人工智能 (AI)
  • 开源项目MusicGen技术详解
  • 【面向对象编程——多继承】
  • 算法题-哈希表01
  • 云平台面试内容(二)