算法学习系列(四十九):最长上升子序列模型(一)

目录

  • 引言
  • 一、最长上升子序列
  • 二、怪盗基德的滑翔翼
  • 三、登山
  • 四、合唱队形
  • 五、友好城市
  • 六、最大上升子序列和

引言

今天学习的是最长上升子序列模型,这种模型我觉得就是我之前说过的就是相当于记忆的过程,记住遇到这种题是用这种模型,下次遇见的时候就能知道了,当然也不完全是死记硬背,相当于是一做了大量的练习,然后考试就可以根据之前做过的大概能知道怎么做,不过考试的时候,基本上就是你能做出来的都是之前有做过类似的题目才行,否则是很难想出来的,也是这个过程就是大量的刷题总结,能从实际问题中抽象出模型或者操作,继续加油吧!


一、最长上升子序列

标签:动态规划、线性DP、最长上升子序列、模板题

思路:时间复杂度: O ( N 2 ) O(N^2) O(N2) 。首先状态定义: f [ i ] f[i] f[i] 因为是线性的所以,一般都用一维来表示,表示所有以 a [ i ] a[i] a[i] 为结尾的严格单调上升子序列的长度的最大值,然后是状态转移方程(集合划分),通常是以最后一步来划分的,如果说最后一步是 a [ i ] a[i] a[i] ,那么之前的元素可能是从 a [ 1 ] , a [ 2 ] , . . . a [ i − 1 ] a[1],a[2],...\ a[i-1] a[1],a[2],... a[i1] 中的任意一个元素,当然也可能是空,因为没有一个合法的方案,这时 f [ i ] = 1 f[i] = 1 f[i]=1 然后最大值就是从这些合法的方案中取一个最大值,方程为: f [ i ] = ∑ j = 1 i − 1 m a x ( f [ i ] , f [ j ] + 1 ) , ( a [ i ] > a [ j ] ) f[i] = \sum_{j=1}^{i-1} max(f[i], f[j]+1),(a[i] > a[j]) f[i]=j=1i1max(f[i],f[j]+1),(a[i]>a[j]) 搜索顺序显而易见为线性的从左到右。

在这里插入图片描述

题目描述:

给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。输入格式
第一行包含整数 N。第二行包含 N 个整数,表示完整序列。输出格式
输出一个整数,表示最大长度。数据范围
1≤N≤1000,−109≤数列中的数≤109输入样例:
7
3 1 2 1 8 5 6
输出样例:
4

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 1010;int n;
int a[N], f[N]; int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 1; i <= n; ++i) cin >> a[i];int res = 0;for(int i = 1; i <= n; ++i){f[i] = 1;for(int j = 1; j < i; ++j){if(a[i] > a[j]) f[i] = max(f[i], f[j] + 1);}res = max(res, f[i]);}cout << res << endl;return 0;
}

二、怪盗基德的滑翔翼

标签:DP、线性DP、最长上升子序列

思路:这道题问的其实是从一个高点可以向一个方向去下降,并且一旦方向确定就不能更改,也就是可以看成是从最长上升子序列和最长下降子序列中找最大的值,那其实就跟上一题是一样的了,只不过这道题要求两遍,详情见代码。

题目描述:

怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出
的足球破坏了。不得已,怪盗基德只能操作受损的滑翔翼逃脱。假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?输入格式
输入数据第一行是一个整数K,代表有K组测试数据。每组测试数据包含两行:第一行是一个整数N,代表有N幢建筑。第二行包含N个不同的整数,每一个对应一幢建筑的高度h,按照
建筑的排列顺序给出。输出格式
对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。数据范围
1≤K≤100,1≤N≤100,0<h<10000
输入样例:
3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10
输出样例:
6
6
9

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 110;int n;
int h[N], f[N];int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);int T; cin >> T;while(T--){cin >> n;for(int i = 1; i <= n; ++i) cin >> h[i];int res = 0;for(int i = 1; i <= n; ++i){f[i] = 1;for(int j = 1; j < i; ++j){if(h[i] > h[j]) f[i] = max(f[i], f[j] + 1);}res = max(res, f[i]);}for(int i = n; i; --i){f[i] = 1;for(int j = n; j > i; --j){if(h[i] > h[j]) f[i] = max(f[i], f[j] + 1);}res = max(res, f[i]);}cout << res << endl;}return 0;
}

三、登山

标签:DP、线性DP、最长上升子序列

思路:这道题是找到一个先上升再下降的和最大的值,可以直接求一遍最长上升子序列再求一遍最长下降子序列,方程为 r e s = ∑ i = 1 n m a x ( r e s , f [ i ] + g [ i ] − 1 ) res = \sum_{i=1}^{n}max(res, f[i] + g[i] - 1) res=i=1nmax(res,f[i]+g[i]1) f[i],g[i]分别为以h[i]结尾的最长上升/下降子序列最大值 \text{f[i],g[i]分别为以h[i]结尾的最长上升/下降子序列最大值} f[i],g[i]分别为以h[i]结尾的最长上升/下降子序列最大值 其实把这个式子一看就能明白

题目描述:

五一到了,ACM队组织大家去登山观光,队员们发现山上一共有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景
点的编号都要大于前一个浏览景点的编号。同时队员们还有另一个登山习惯,就是不连续浏览海拔相同的两个景点,并且一旦开始下山,就不再向上走了。队员们希望在满足上面条件的同时,尽可能多的浏览景点,你能帮他们找出最多可能浏览的景点数么?输入格式
第一行包含整数N,表示景点数量。第二行包含N个整数,表示每个景点的海拔。输出格式
输出一个整数,表示最多能浏览的景点数。数据范围
2≤N≤1000
输入样例:
8
186 186 150 200 160 130 197 220
输出样例:
4

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 1010;int n;
int h[N], f[N], g[N];int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 1; i <= n; ++i) cin >> h[i];for(int i = 1; i <= n; ++i){f[i] = 1;for(int j = 1; j < i; ++j){if(h[i] > h[j]) f[i] = max(f[i], f[j] + 1);}}for(int i = n; i; --i){g[i] = 1;for(int j = n; j > i; --j){if(h[i] > h[j]) g[i] = max(g[i], g[j] + 1);}}int res = 0;for(int i = 1; i <= n; ++i) res = max(res, f[i] + g[i] - 1);cout << res << endl;return 0;
}

四、合唱队形

标签:DP线性、DP、最长上升子序列、前后缀分解

思路:这道题就是跟上一题基本上是一模一样的,只不过问的是最少需要移除多少位同学,那么就是求满足条件的最大人数,那也就是上一题的答案了,然后用总人数一减就行了。

题目描述:

N 位同学站成一排,音乐老师要请其中的 (N−K) 位同学出列,使得剩下的 K 位同学排成合唱队形。     合唱队形是指这样的一种队形:设 K 位同学从左到右依次编号为 1,2…,K,他们的身高分别为 T1,T2,…,TK,  则他们的
身高满足 T1<…<Ti>Ti+1>…>TK(1≤i≤K)。     你的任务是,已知所有 N 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。输入格式
输入的第一行是一个整数 N,表示同学的总数。第二行有 N 个整数,用空格分隔,第 i 个整数 Ti 是第 i 位同学的身高(厘米)。输出格式
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。数据范围
2≤N≤100,130≤Ti≤230
输入样例:
8
186 186 150 200 160 130 197 220
输出样例:
4

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 1010;int n;
int h[N], f[N], g[N];int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 1; i <= n; ++i) cin >> h[i];for(int i = 1; i <= n; ++i){f[i] = 1;for(int j = 1; j < i; ++j){if(h[i] > h[j]) f[i] = max(f[i], f[j] + 1);}}for(int i = n; i; --i){g[i] = 1;for(int j = n; j > i; --j){if(h[i] > h[j]) g[i] = max(g[i], g[j] + 1);}}int res = 0;for(int i = 1; i <= n; ++i) res = max(res, f[i] + g[i] - 1);cout << n - res << endl;return 0;
}

五、友好城市

标签:DP、线性DP、最长上升子序列

思路:首先这些城市基本上就是如下图的关系,找出其中最多并且不相交的线条,我们发现如果它们不相交的话,那么它们的坐标肯定是单调的,如果我们把上面一端固定住,按照上面城市的坐标顺序看下面的城市,那么如果要不相交,那么其下面的坐标肯定是严格单调上升的。所以先拿 p a i r pair pair 存排个序,然后求其另一个坐标的最长上升子序列,就是我们要求的答案。

题目描述:

Palmia国有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以
避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航线不相交的情况下,被批准的申请尽量多。输入格式
第1行,一个整数N,表示城市数。第2行到第n+1行,每行两个整数,中间用1个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。输出格式
仅一行,输出一个整数,表示政府所能批准的最多申请数。数据范围
1≤N≤5000,0≤xi≤10000
输入样例:
7
22 4
2 6
10 3
15 12
9 8
17 17
4 2
输出样例:
4

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 5010;int n;
int f[N];
PII city[N];int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 1; i <= n; ++i) cin >> city[i].x >> city[i].y;sort(city+1, city+1+n);int res = 0;for(int i = 1; i <= n; ++i){f[i] = 1;for(int j = 1; j < i; ++j){if(city[i].y > city[j].y) f[i] = max(f[i], f[j] + 1);}res = max(res, f[i]);}cout << res << endl;return 0;
}

六、最大上升子序列和

标签:DP、线性DP、最长上升子序列

思路:其实本质还是上升子序列,只不过 f [ i ] f[i] f[i] 存的不是长度了,而存的是和的最大值。状态表示: f [ i ] f[i] f[i] 表示以 a [ i ] a[i] a[i] 为结尾的最大上升子序列和,那么上一步可能是 a [ i ] a[i] a[i] 之前的任何一个数,也可能是空值,在这些集合中取最大值。状态转移方程如下: f [ i ] = ∑ j = 1 i − 1 m a x ( f [ i ] , f [ j ] + a [ i ] ) , ( a [ i ] > a [ j ] ) f[i] = \sum_{j=1}^{i-1} max(f[i], f[j]+a[i]),(a[i] > a[j]) f[i]=j=1i1max(f[i],f[j]+a[i]),(a[i]>a[j])

题目描述:

一个数的序列 bi,当 b1<b2<…<bS 的时候,我们称这个序列是上升的。对于给定的一个序列(a1,a2,…,aN),我们可以得到一些上升的子序列(ai1,ai2,…,aiK),这里1≤i1<i2<…<iK≤N。比如,对于序列(1,7,3,5,9,4,8),有它的一些上升子序列,如(1,7),(3,4,8)等等。这些子序列中和最大为18,为子序列(1,3,5,9)的和。你的任务,就是对于给定的序列,求出最大上升子序列和。注意,最长的上升子序列的和不一定是最大的,比如序列(100,1,2,3)的最大上升子序列和为100,而最长上升子序列为(1,2,3)。输入格式
输入的第一行是序列的长度N。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000(可能重复)。输出格式
输出一个整数,表示最大上升子序列和。数据范围
1≤N≤1000
输入样例:
7
1 7 3 5 9 4 8
输出样例:
18

示例代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;
typedef pair<int,int> PII;
#define x first
#define y secondconst int N = 1010;int n;
int a[N], f[N];int main()
{ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;for(int i = 1; i <= n; ++i) cin >> a[i];int res = 0;for(int i = 1; i <= n; ++i){f[i] = a[i];for(int j = 1; j < i; ++j){if(a[i] > a[j]) f[i] = max(f[i], f[j] + a[i]);}res = max(res, f[i]);}cout << res << endl;return 0;
}

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

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

相关文章

打开电脑底部导航栏的任务

from pywinauto import Application app Application("uia").connect(path"explorer") app["任务栏"].print_control_identifiers() task app["任务栏"].child_window(title"酷狗音乐", auto_id"D:\soft\kugou\KGMus…

Proxmox VE 实现批量增加多网络

前言 实现批量创建多网络&#xff0c;更改主机名称&#xff0c;hosts解析 初始化网卡&#xff0c;主机名称&#xff0c;hosts解析&#xff0c;重启网卡 我的主机六个网卡&#xff0c;使用的有四个网卡&#xff0c;以下一键创建和初始化主机名称我是以硬件的SN号最为主机的名…

Matlab调C/C++简单模板例子

如果你是需要快速搭建一个matlab调c/c环境&#xff0c;这篇文章可以参考 有了c代码&#xff0c;想在matlab里面调用&#xff0c;可以参考我这个模板 matlab调用代码&#xff1a; clear all close all clcinput1 1; input2 2;[output1,output2] mexfunction(input1,input2);…

普通人做抖音小店真的能赚钱吗?可以,但更取决于个人

大家好&#xff0c;我是电商花花。 现在做抖音小店的基本上都是一些新商家&#xff0c;对于我们众多零基础的朋友来说&#xff0c;是期待也是一份挑战。 抖音小店作为一个充满机会的新兴平台&#xff0c;许多人都欣喜的投入其中&#xff0c;期望能够借此来改变自己的命运&…

西门子电动阀门

一、西门子电动调节阀 二、西门子电动调节蝶阀 1、阀门 2、执行器

客户资料不翼而飞?企业数据保护攻略

在数字化经济时代&#xff0c;企业的客户资料等同于商业生命线&#xff0c;一旦泄露&#xff0c;后果不堪设想。例如&#xff0c;2017年Equifax的数据泄露事件&#xff0c;造成超过1.4亿用户的个人信息外泄&#xff0c;不仅给用户带来风险&#xff0c;也让公司名誉受损&#xf…

BackTrader 中文文档(二)

原文&#xff1a;www.backtrader.com/ 概念 平台概念 原文&#xff1a;www.backtrader.com/docu/concepts/ 这是平台某些概念的集合。它试图收集可在使用平台时有用的信息片段。 开始之前 所有小代码示例都假设以下导入可用&#xff1a; import backtrader as bt import ba…

移植speexdsp到OpenHarmony标准系统④

五、在OpenHarmony编译体系下增量编译Speexdsp 建议先增量编译生成三方库的动态链接库和可执行文件,验证是否成功把三方库加入OpenHarmonybian编译体系。 成功编译出so和可执行文件&#xff0c;即成功把三方库加入到ohos编译体系。之后还要验证三方库在ohos运行&#xff0c;功…

英语新概念2-回译法-lesson8

乔桑德斯有着我们镇上最漂亮的花园。附近的每一个人每年都参加“最美花园比赛”&#xff0c;但是每年都是乔赢得比赛。比尔芙丽丝的花园比乔的花园大&#xff0c;但是乔的花园更有趣。他有整洁的小径以及一座木桥架在一个池塘上。我也喜欢花园&#xff0c;但是我不喜欢辛勤劳作…

企业网络日益突出的难题与SD-WAN解决方案

随着企业规模的迅速扩张和数字化转型的深入推进&#xff0c;企业在全球范围内需要实现总部、分支机构、门店、数据中心、云等地点的网络互联、数据传输和应用加速。SD-WAN作为当今主流解决方案&#xff0c;在网络效率、传输质量、灵活性和成本等方面远远超越传统的互联网、专线…

【经典算法】LeetCode 136:只出现一次的数字(Java/C/Python3实现含注释说明,Easy)

个人主页&#xff1a; 进朱者赤 阿里非典型程序员一枚 &#xff0c;记录平平无奇程序员在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法&#xff08;公众号同名&#xff09; 目录 题目描述思路及实现方式一&#xff1a;使用异或运算&#xff08;推荐&#xff09;思…

【论文笔记 | 异步联邦】Asynchronous Federated Optimization

论文信息 Asynchronous Federated Optimization&#xff0c;OPT2020: 12th Annual Workshop on Optimization for Machine Learning&#xff0c;不属于ccfa introduction 背景&#xff1a;联邦学习有三个关键性质 任务激活不频繁&#xff08;比较难以达成条件&#xff09;&…

C++ ─── 操作符重载和赋值重载

目录 赋值运算符重载 运算符重载 赋值运算符重载&#xff08;赋值重载operator&#xff09; 前置和后置重载 赋值运算符重载 运算符重载 C为了增强代码的可读性引入了运算符重载 &#xff0c; 运算符重载是具有特殊函数名的函数 &#xff0c;也具有其返回值类型&#xff0c…

某手滑块逆向流程分析

声明 本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 目标网站 aHR0cHM6Ly93d3cua3VhaXNob3UuY29tL3Byb2ZpbGUvM3h4Ymt3ZDhta250ZWFj 参数流程…

开发工具:推荐一款实用的浏览器查看json插件(附下载)

目录 插件简介 支持的 mime类型 插件特点 “Tree”视图支持的快捷键列表: “Code”视图支持的快捷键列表: 安装方法 使用效果 插件简介 “JSON Beautifier”扩展程序是一个实用工具&#xff0c;可方便查看、编辑、格式化、验证和导出JSON页面。该扩展程序无需任何设置即可运行…

# Nacos 服务发现-Spring Cloud Alibaba 综合架构实战(四) -实现 service2 子模块。

Nacos 服务发现-Spring Cloud Alibaba 综合架构实战&#xff08;四&#xff09; -实现 service2 子模块。 1、在 service2 子模块下的 service-2-api 二级子工程中&#xff0c;定义服务接口 创建 ProviderService.java /*** C:\java-test\idea2019\nacos_discovery\nacos-mi…

【Java开发指南 | 第三篇】Java 空行、强制类型转换及基本数据类型

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 Java 空行强制类型转换Java 基本数据类型内置数据类型引用类型 Java 空行 空白行或者有注释的行&#xff0c;Java 编译器都会忽略掉。 强制类型转换 当需要将一个数据类型转换为另一个数据类型时&#xff0c…

Cat6 屏蔽与非屏蔽:决定最佳选择

Cat6 电缆通常用于现代网络中的高速以太网数据传输。它们有两种类型&#xff1a;屏蔽 &#xff08;STP&#xff09; 和非屏蔽 &#xff08;UTP&#xff09;。这两种电缆之间的主要区别在于它们对电磁干扰 &#xff08;EMI&#xff09; 和串扰的抵抗力。 屏蔽 Cat6 电缆具有额外…

python代码打包exe文件

创建和激活虚拟环境 创建虚拟环境 首先让我们创建一个虚拟环境。你可以使用 venv 模块来创建一个虚拟环境。以下是创建虚拟环境的步骤&#xff1a; 打开终端&#xff08;或命令提示符&#xff09;&#xff1a;进入你想要创建虚拟环境的目录。 运行以下命令来创建虚拟环境&a…

谷歌pixel6/7pro等手机WiFi不能上网,显示网络连接受限

近期在项目中遇到一个机型出现的问题,先对项目代码进行排查,发现别的设备都能正常运行,就开始来排查机型的问题,特意写出来方便后续查看,也方便其它开发者来自查。 设备机型:Pixel 6a 设备安卓版本:13 该方法无需root,只需要电脑设备安装adb(即Android Debug Bridge…