动态规划之线性DP

article/2025/9/29 9:13:05

🐏🐏🐏

  • 🐏动态规划之线性DP🐏
    • 🐏写在前面🐏
    • 🐏数字三角形🐏
    • 🐏最长上升子序列🐏
    • 🐏最长上升子序列 II🐏
    • 🐏最长公共子序列🐏
    • 🐏写到最后🐏

🐏动态规划之线性DP🐏

🐏写在前面🐏

之前讲过背包问题,不知道大家忘了吗,如果忘了可以点这里,这次是线性DP
看完本篇文章觉得不错的话记得点赞👍,收藏⭐,还有问题也可以评论留言💬

🐏数字三角形🐏

在这里插入图片描述
状态表示:f[i,j],到点i,j的最大路径

状态计算:f[i,j] = MAX(f[i-1,j-1]+a[i,j],f[i-1,j]+a[i,j])
在这里插入图片描述
看图,以例题为例,将它看成五行五列的三角形,每个点都可以用坐标表示。那么我们可以得知到一个数的最大路径要么来自左上,要么来自右上。左上的数用f[i-1,j-1]表示,右上的数f[i-1,j]表示,因此我们就有了状态转移公式:

f[i,j] = MAX(f[i-1,j-1]+a[i,j],f[i-1,j]+a[i,j])

所以就有了最终的代码:

#include <iostream>
#include <algorithm>using namespace std;const int N = 510, INF = 1e9;int n;
int a[N][N];
int f[N][N];int main()
{scanf("%d", &n);for (int i = 1; i <= n; i ++ )for (int j = 1; j <= i; j ++ )scanf("%d", &a[i][j]);for (int i = 0; i <= n; i ++ )for (int j = 0; j <= i + 1; j ++ )//注意这里j从0到i+1,因为对于边界点,它的上一层只有一条路径通向它f[i][j] = -INF;//初始化近似为-∞f[1][1] = a[1][1];for (int i = 2; i <= n; i ++ )for (int j = 1; j <= i; j ++ )f[i][j] = max(f[i - 1][j - 1] + a[i][j], f[i - 1][j] + a[i][j]);int res = -INF;for (int i = 1; i <= n; i ++ ) res = max(res, f[n][i]);printf("%d\n", res);return 0;
}

🐏最长上升子序列🐏

在这里插入图片描述
状态表示:f[i]表示从第一个数字开始算,以w[i]结尾的最大的上升序列。(以w[i]结尾的所有上升序列中属性为最大值的那一个)

状态计算(集合划分):j∈(0,1,2,…,i-1), 在w[i] > w[j]时,
f[i] = max(f[i], f[j] + 1)。
有一个边界,若前面没有比i小的,f[i]为1(自己为结尾)。

最后在找f[i]的最大值。

时间复杂度
O(n2) 状态数(n) * 转移数(n)
在这里插入图片描述
看图, 首先 f[i]f[i] 的含义是以 w[i]结尾的最长上升子序列的长度
初始值 f[i]=1,i∈[0,n−1],表示自己就是最长上升子序列,长度为 1
接下来考虑状态转移,把前 i−1个数字中所有满足条件 w[j]<w[i](因为要求是上升子序列) 的 j 找出来,那么 f[i] 就可以试着更新为以 w[j] 结尾的最长上升子序列的长度 再加上 自己的长度 1,但可能更新完的结果没有之前更新过的 f[i] 大,最后两者取一个 max,所以状态转移方程就是 f[i]=max(f[i],f[j]+1)

#include <iostream>using namespace std;const int N = 1010;int n;
int w[N], f[N];int main() {cin >> n;for (int i = 0; i < n; i++) cin >> w[i];int mx = 1;    // 找出所计算的f[i]之中的最大值,边算边找for (int i = 0; i < n; i++) {f[i] = 1;    // 设f[i]默认为1,找不到前面数字小于自己的时候就为1for (int j = 0; j < i; j++) {if (w[i] > w[j]) f[i] = max(f[i], f[j] + 1);    // 前一个小于自己的数结尾的最大上升子序列加上自己,即+1}mx = max(mx, f[i]);}cout << mx << endl;return 0;
}

🐏最长上升子序列 II🐏

在这里插入图片描述
会发现II的数据范围变了,那我们就得做优化,怎么优化呢?

状态表示:f[i]表示长度为i的最长上升子序列,末尾最小的数字。(长度为i的最长上升子序列所有结尾中,结尾最小min的) 即长度为i的子序列末尾最小元素是什么。

状态计算:对于每一个w[i], 如果大于f[cnt-1] (下标从0开始,cnt长度的最长上升子序列,末尾最小的数字),那就cnt+1,使得最长上升序列长度+1,当前末尾最小元素为w[i]。 若w[i]小于等于f[cnt-1],说明不会更新当前的长度,但之前末尾的最小元素要发生变化,找到第一个 大于或等于 (这里不能是大于) w[i],更新以那时候末尾的最小元素。

f[i]一定以一个单调递增的数组,所以可以用二分法来找第一个大于或等于w[i]的数字。

时间复杂度
O(nlogn)状态数(n) * 转移数(logn)

#include <iostream>using namespace std;const int N = 1010;
int n, cnt;
int w[N], f[N];int main() {cin >> n;for (int i = 0 ; i < n; i++) cin >> w[i];f[cnt++] = w[0];for (int i = 1; i < n; i++) {if (w[i] > f[cnt-1]) f[cnt++] = w[i];else {int l = 0, r = cnt - 1;while (l < r) {int mid = (l + r) >> 1;if (f[mid] >= w[i]) r = mid;else l = mid + 1;}f[r] = w[i];}}cout << cnt << endl;return 0;
}

🐏最长公共子序列🐏

在这里插入图片描述
在这里插入图片描述
集合表示:f[i][j]表示a的前i个字母,和b的前j个字母的最长公共子序列长度

集合划分:以a[i],b[j]是否包含在子序列当中为依据,因此可以分成四类:

①a[i]不在,b[j]不在

max=f[i−1][j−1]

②a[i]a[i]不在,b[j]b[j]在
看似是max=f[i−1][j] , 实际上无法用f[i−1][j]表示,因为f[i−1][j]表示的是在a的前i-1个字母中出现,并且在b的前j个字母中出现,此时b[j]不一定出现,这与条件不完全相等,条件给定是a[i]一定不在子序列中,b[j]一定在子序列当中,但仍可以用f[i−1][j]来表示,原因就在于条件给定的情况被包含在f[i−1][j]中,即条件的情况是f[i−1][j]的子集,而求的是max,所以对结果不影响。

例如:要求a,b,c的最大值可以这样求:max(max(a,b),max(b,c))虽然b被重复使用,但仍能求出max,求max只要保证不漏即可。

③a[i],b[j]不在 原理同②

④a[i]在,b[j]在 max=f[i−1][j−1]+1

实际上,在计算时,①包含在②和③的情况中,所以①不用考虑

#include <iostream>using namespace std;const int N = 1010;int n , m;
char a[N] , b[N];
int f[N][N];
int main()
{cin >> n >> m;cin >> a + 1 >> b + 1;for(int i = 1 ; i <= n ; i++)for(int j = 1 ; j <= m ; j++){f[i][j] = max(f[i - 1][j] , f[i][j - 1]);//2和3的情况一定存在,所以可以无条件优先判断if(a[i] == b[j]) f[i][j] = max(f[i][j] , f[i - 1][j - 1] + 1);}                                                       cout << f[n][m] << endl;return 0;
}

🐏写到最后🐏

最后看到这了,如果觉得自己有收获的话,可以给博主点个关注哦
觉得本篇文章不错的话记得点赞👍,收藏⭐,还有问题也可以评论留言💬
你的支持将是我继续创作的最大动力❤️❤️❤️
由于作者水平有限,如有错误和不准确之处在所难免,本人也很想知道这些错误,恳望读者批评指正!


http://chatgpt.dhexx.cn/article/23NZ7nnJ.shtml

相关文章

DP(动态规划)入门基础详解

DP总结&#xff08;写得这么辛苦点个赞呗&#xff01;&#xff09; DP基本概要&#xff1a; 动态规划算法把原问题视作若干个重叠子问题的逐层递进,每一个子问题的求解过程都构成一个“阶段”。在完成前一个阶段的计算后,动态规划才会执行下一阶段的计算。 无后效性 &#xf…

非常好的动态规划(DP)总结

转自&#xff1a; http://cppblog.com/menjitianya/archive/2015/10/23/212084.html 目录 一、动态规划初探 1、递推 2、记忆化搜索 3、状态和状态转移 4、最优化原理和最优子结构 5、决策和无后效性 二、动态规划的经典模型 1、线性模型 2、区间模型 3、背包模型 4、状态压…

动态规划 DP (一)

1.动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09; 维基百科的定义说的很清楚&#xff1a; 动态规划不能解决所有的问题&#xff0c; 只能应用于有最优子结构的问题。例如背包问题、最长公共子序列问题、最短路径问题等。 最优子结构&#xff1a;局部…

动态规划(DP)通俗讲解

参考 徐凯强 Andy 动态规划中递推式的求解方法不是动态规划的本质。 我曾经作为省队成员参加过NOI&#xff0c;保送之后也给学校参加NOIP的同学多次讲过动态规划&#xff0c;我试着讲一下我理解的动态规划&#xff0c;争取深入浅出。希望你看了我的答案&#xff0c;能够喜欢上动…

【算法之动态规划(一)】动态规划(DP)详解

一、基本概念 动态规划(dynamic programming)是 运筹学 的一个分支&#xff0c;是求解决策过程(decision process)最优化的数学方法。20世纪50年代初 美国 数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时&#xff0c;提出了著名的最优…

动态规划(dp)的总结

动态规划(dp)的总结 动态规划只要找到子问题&#xff0c;写起来就很简单&#xff0c;通常最多就二维dp数组即可解决问题&#xff0c;顶多再来个双dp&#xff0c;再加点逆向思维……下面列出我见过的子问题&#xff0c;别栽在dp上了&#xff0c;求求了。 能用dp做&#xff0c;…

数据结构与算法——动态规划(DP)

文章目录 1. 应用场景2. DP状态2.1 最优子结构2.2 无后效性2.3 解题思路 3. 问题类别3.1 线性DP3.1.1 经典问题3.1.1.1 [LeetCode 300. 最长上升子序列](https://leetcode-cn.com/problems/longest-increasing-subsequence/)3.1.1.2 [LeetCode 1143. 最长公共子序列](https://l…

关于动态规划(dp)

**动态规划(DP) 一.基本概念 动态规划&#xff08;英语&#xff1a;Dynamic programming&#xff0c;简称DP&#xff09;是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的&#xff0c;通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 它针对满足…

动态规划(DP)的原理、实现及应用

文章目录 1. 由一个例子说开&#xff1a; 斐波那契&#xff08;fibonacci&#xff09;数列 性能测试原因分析2. 记忆化搜索3. 动态规划&#xff08;Dynamic Programming&#xff0c;DP&#xff09; 最优子结构总结一下这几个解法&#xff1a;几个例题 LeetCode 70 Climbing St…

Hi3519AV100与Hi3559AV100在芯片规格 上主要差异

表1-1简要对比了Hi3519AV100与Hi3559AV100在规格方面的差异&#xff0c;Hi3519AV100的具体规格请参见《Hi3519AV100 ultra-HD Mobile Camera SoC 用户指南》。

海思平台(hi3559av100)异构多系统的使用Linux(2*A53+2*A73)+liteos(A53)+liteos(M7)

在文档《SDK安装及升级使用说明》中有对linuxliteos异构多系统的烧写有介绍。这里对其中的一些注意的地方记录以下&#xff0c;以备查验。 由于我的目标是要搭建一个ISP调试环境&#xff0c;就是使用海思的ittp_stream工具能够连接上开发板&#xff0c;并能够实时查看摄像头的…

M302H-ZN-Hi3798MV300/MV300H-当贝纯净桌面-卡刷固件包

M302H-ZN-Hi3798MV300&#xff0f;MV300H-当贝纯净桌面-卡刷固件包-内有教程 特点&#xff1a; 1、适用于对应型号的电视盒子刷机&#xff1b; 2、开放原厂固件屏蔽的市场安装和u盘安装apk&#xff1b; 3、修改dns&#xff0c;三网通用&#xff1b; 4、大量精简内置的没用…

华为海思 hikey970 详细介绍

前几天申请到了华为的开发板&#xff1a;hikey970 用来做项目的。 板子是这样的: 下面是在网中收集到的信息总结&#xff1a; 基于麒麟970的AI智慧算力&#xff0c;HiKey 970除了支持CPU和GPU的AI运算外&#xff0c;还支持基于NPU的神经网络计算硬件加速。 公开资料显示&am…

海思Hi3519AV100 emmc flash方式 linux系统移植 hitool工具烧写

因为我这里的海思文档只有SPI NOR Flash方式的详细烧写步骤&#xff0c;没有emmc方式的&#xff0c;本文提供一个自己成功的案例仅供参考和记录 1. 准备SDK、安装交叉编译工具、编译osdrv 1.1 解压SDK包 将Hi3519AV100_SDK_Vx.x.x.x.tgz文件放入ubuntu系统下&#xff08;wind…

海思3559:MMZ内存、OS内存配置

前言 海思3559的DDR最大支持到8GB hi3559av100芯片的内存地址范围 (1)通过查阅数据手册可知《Hi3559AV100 专业型 Smart IP Camera SoC 用户指南》&#xff0c;芯片的内存地址范围是0x4000_0000-0x23FFF_FFFF&#xff0c;最大能支持8G内存&#xff1b;   (2)海思芯片把内存分…

劲爆!java架构师百度网盘

第一份资料:Kafka实战笔记 Kafka入门为什么选择KafkaKarka的安装、管理和配置Kafka的集群第一个Kafka程序afka的生产者 Kafka的消费者深入理解Kafka可靠的数据传递

10本Java架构师必读书籍推荐

##### 1.《大型网站系统与Java中间件开发实践》 本书围绕大型网站和支撑大型网站架构的 Java 中间件的实践展开介绍。从分布式系统的知识切入&#xff0c;让读者对分布式系统有基本的了解&#xff1b;然后介绍大型网站随着数据量、访问量增长而发生的架构变迁&#xff1b;接着…

Java架构师需要哪些知识?

如何才能达到Java架构师技术要求标准&#xff1f;Java架构师需要熟练掌握复杂的数据结构和算法、熟练使用linux操作系统&#xff0c;Linux线上排除故障、熟悉tcp协议、系统集群、[负载均衡]、反向代理、动静分离&#xff0c;网站静态化、数据库设计能力、队列中间件等知识。 一…

JAVA架构师之路十六:设计模式之责任链模式

JAVA架构师之路十五&#xff1a;设计模式之策略模式 责任链模式 1. 责任链模式2. 登陆案例 3. 登陆案例优化 人生的游戏不在于拿了一副好牌&#xff0c;而在于怎样去打好坏牌&#xff0c;世上没有常胜将军&#xff0c;勇于超越自我者才能得到最后的奖杯。 1. 责任链模式 定义…

BAT面试高级进阶,Java架构师之路

说明 Java生鲜电商平台中由于采用了微服务架构进行业务的处理&#xff0c;买家&#xff0c;卖家&#xff0c;配送&#xff0c;销售&#xff0c;供应商等进行服务化&#xff0c;但是不可避免存在分布式事务的问题。 业界有很多的解决方案&#xff0c;对此我相信大家都百度一下…