动态规划系列 | 最长上升子序列模型(上)

文章目录

    • 最长上升子序列回顾
      • 题目描述
      • 问题分析
      • 程序代码
      • 复杂度分析
    • 怪盗基德的滑翔翼
      • 题目描述
        • 输入格式
        • 输出格式
      • 问题分析
      • 程序代码
      • 复杂度分析
    • 登山
      • 题目描述
        • 输入格式
        • 输出格式
      • 问题分析
      • 程序代码
      • 复杂度分析
    • 合唱队形
      • 题目描述
        • 输入格式
        • 输出格式
      • 问题分析
      • 程序代码
      • 复杂度分析
    • 友好城市
      • 题目描述
        • 输入格式
        • 输出格式
      • 问题分析
      • 程序代码
      • 复杂度分析
    • 最大上升子序列和
      • 题目描述
        • 输入格式
        • 输出格式
      • 问题分析
      • 程序代码
      • 复杂度分析

最长上升子序列回顾

题目描述

给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。

问题分析

状态表示dp[i]表示所有以a[i]结尾的严格单调上升子序列的最大长度。

状态计算dp[i] = max(dp[i], dp[k] + 1),其中需要满足a[k] < a[i]

程序代码

#include <iostream>
using namespace std;const int N = 1010;
int a[N], dp[N];int main()
{int n;cin >> n;for(int i = 1; i <= n; i++) {cin >> a[i];}int res = 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);}}res = max(res, dp[i]);}cout << res << endl;return 0;
}

复杂度分析

时间复杂度为 O ( N 2 ) O(N^2) O(N2)

怪盗基德的滑翔翼

题目描述

怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。

而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。

有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。

不得已,怪盗基德只能操作受损的滑翔翼逃脱。

假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。

初始时,怪盗基德可以在任何一幢建筑的顶端。

他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。

因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。

他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。

请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?

输入格式

输入数据第一行是一个整数K,代表有K组测试数据。

每组测试数据包含两行:第一行是一个整数N,代表有N幢建筑。第二行包含N个不同的整数,每一个对应一幢建筑的高度h,按照建筑的排列顺序给出。

输出格式

对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。

问题分析

这道题可以转化为两个方向的最长上升子序列问题。【裸题,相信你可以直接 A 了】

程序代码

#include <iostream>
using namespace std;const int N = 110;
int a[N], dp[N];int main()
{int t;cin >> t;while( t-- ) {int n;cin >> n;int res = 0;for(int i = 1; i <= n; i++) {cin >> a[i];}// 正向求解LISfor(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);}res = max(dp[i], res);}// 反向求解LISfor(int i = n; i >= 1; i--) {dp[i] = 1;for(int j = n; j > i; j--) {if(a[j] < a[i])  dp[i] = max(dp[i], dp[j] + 1);}res = max(dp[i], res);}cout << res << endl;}return 0;
}

复杂度分析

时间复杂度为 O ( N 2 ) O(N^2) O(N2)

登山

题目描述

五一到了,ACM队组织大家去登山观光,队员们发现山上一共有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景点的编号都要大于前一个浏览景点的编号。

同时队员们还有另一个登山习惯,就是不连续浏览海拔相同的两个景点,并且一旦开始下山,就不再向上走了。

队员们希望在满足上面条件的同时,尽可能多的浏览景点,你能帮他们找出最多可能浏览的景点数么?

输入格式

第一行包含整数N,表示景点数量。

第二行包含N个整数,表示每个景点的海拔。

输出格式

输出一个整数,表示最多能浏览的景点数。

问题分析

对于这道题,本质上是找一个分割点k,求以 k 结尾的最长上升子序列长度f[k]和以 k 开头的最长下降子序列g[k],然后求f[k] + g[k]的最大值。

程序代码

#include <iostream>
using namespace std;const int N = 1010;
int a[N], f[N], g[N];int main()
{int n;cin >> n;for(int i = 1; i <= n; i++) {cin >> a[i];}// 正向求解LISfor(int i = 1; i <= n; i++) {f[i] = 1;for(int j = 1; j < i; j++) {if(a[j] < a[i])  f[i] = max(f[i], f[j] + 1);}}// 反向求解LIS就是以i开头的最长下降子序列for(int i = n; i >= 1; i--) {g[i] = 1;for(int j = n; j > i; j--) {if(a[j] < a[i])  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;
}

复杂度分析

时间复杂度为 O ( N 2 ) O(N^2) O(N2)

合唱队形

题目描述

N 位同学站成一排,音乐老师要请其中的 (N−K) 位同学出列,使得剩下的 K 位同学排成合唱队形。

合唱队形是指这样的一种队形:设 K 位同学从左到右依次编号为 1,2…,K,他们的身高分别为 T 1 , T 2 , … , T K T_1,T_2,…,T_K T1T2TK,  则他们的身高满足 T 1 < . . . < T i > T i + 1 > . . . > T K ( 1 ≤ i ≤ K ) T_1 < ... < T_i > T_{i+1} > ... > T_K(1 \leq i \leq K) T1<...<Ti>Ti+1>...>TK(1iK)

你的任务是,已知所有 N 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入格式

输入的第一行是一个整数 N,表示同学的总数。

第二行有 N 个整数,用空格分隔,第 i 个整数 T i T_i Ti 是第 i 位同学的身高(厘米)。

输出格式

输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。

问题分析

这道题其实就是用总数 n 减去上面那道登山问题求出来的最多能浏览的景点数。

程序代码

#include <iostream>
using namespace std;const int N = 1010;
int a[N], f[N], g[N];int main()
{int n;cin >> n;for(int i = 1; i <= n; i++) {cin >> a[i];}// 正向求解LISfor(int i = 1; i <= n; i++) {f[i] = 1;for(int j = 1; j < i; j++) {if(a[j] < a[i])  f[i] = max(f[i], f[j] + 1);}}// 反向求解LIS就是以i开头的最长下降子序列for(int i = n; i >= 1; i--) {g[i] = 1;for(int j = n; j > i; j--) {if(a[j] < a[i])  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;
}

复杂度分析

时间复杂度为 O ( N 2 ) O(N^2) O(N2)

友好城市

题目描述

Palmia国有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。

北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。

每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。

编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航线不相交的情况下,被批准的申请尽量多。

输入格式

第1行,一个整数N,表示城市数。

第2行到第n+1行,每行两个整数,中间用1个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。

输出格式

仅一行,输出一个整数,表示政府所能批准的最多申请数。

问题分析

前提条件:每个城市有且仅有一个友好城市在对岸,而且不同城市的友好城市不相同

这道题要求在满足如下约束的情况下,建立尽可能多的桥

  1. 每个城市上只能建立一座桥
  2. 只有友好城市之间能建立一座桥
  3. 所有的桥之间不能相交

在这里插入图片描述

以南岸的城市为基准,我们可以发现,对于任意一种建桥的可行方案,北岸的城市位置都是严格单调递增的。

换言之,我们建立一个二元组<a, b>a表示南岸的城市位置,b表示北岸的城市位置。若两个桥之间不相交,则必有当a1 < a2时,b1 < b2

因此,我们可以将所有的友好城市建立成一组二元组<a, b>,将二元组按照南岸的位置a升序排序,然后找关于b的最长上升子序列。

程序代码

#include <iostream>
#include <algorithm>
using namespace std;typedef pair<int, int> PII;const int N = 5050;int n;
PII a[N];
int dp[N];int main()
{cin >> n;for(int i = 0; i < n; i++) {cin >> a[i].first >> a[i].second;}sort(a, a + n);int res = 0;for(int i = 0; i < n; i++) {dp[i] = 1;for(int j = 0; j < i; j++) {if(a[i].second > a[j].second) {dp[i] = max(dp[i], dp[j] + 1);}}res = max(res, dp[i]);}cout << res << endl;return 0;
}

复杂度分析

时间复杂度为 O ( N 2 ) O(N^2) O(N2)

最大上升子序列和

题目描述

一个数的序列 b i b_i bi,当 b 1 < b 2 < … < b S b_1<b_2<…<b_S b1<b2<<bS 的时候,我们称这个序列是上升的。

对于给定的一个序列 ( a 1 , a 2 , … , a N ) (a_1,a_2,…,a_N) (a1,a2,,aN),我们可以得到一些上升的子序列 ( a i 1 , a i 2 , … , a i K ) (a_{i1},a_{i2},…,a_{iK}) (ai1,ai2,,aiK),这里 1 ≤ i 1 < i 2 < … < i K ≤ N 1≤i_1<i_2<…<i_K≤N 1i1<i2<<iKN

比如,对于序列 ( 1 , 7 , 3 , 5 , 9 , 4 , 8 ) (1,7,3,5,9,4,8) (1,7,3,5,9,4,8),有它的一些上升子序列,如 ( 1 , 7 ) , ( 3 , 4 , 8 ) (1,7),(3,4,8) (1,7),(3,4,8) 等等。

这些子序列中和最大为18,为子序列 ( 1 , 3 , 5 , 9 ) (1,3,5,9) (1,3,5,9) 的和。

你的任务,就是对于给定的序列,求出最大上升子序列和。

注意,最长的上升子序列的和不一定是最大的,比如序列 ( 100 , 1 , 2 , 3 ) (100,1,2,3) (100,1,2,3) 的最大上升子序列和为100,而最长上升子序列为 ( 1 , 2 , 3 ) (1,2,3) (1,2,3)

输入格式

输入的第一行是序列的长度N。

第二行给出序列中的N个整数,这些整数的取值范围都在0到10000(可能重复)。

输出格式

输出一个整数,表示最大上升子序列和。

问题分析

这道题对最长上升子序列问题的状态定义和状态计算进行一定的微调即可。

状态表示dp[i]表示所有以a[i]结尾的严格单调上升子序列的最大和。

状态计算dp[i] = max(dp[i], dp[k] + a[i]),其中需要满足a[k] < a[i]

程序代码

#include <iostream>
#include <algorithm>
using namespace std;const int N = 1010;
int a[N], dp[N];
int n;int main()
{cin >> n;for(int i = 1; i <= n; i++) {cin >> a[i];}int res = 0;for(int i = 1; i <= n; i++) {dp[i] = a[i];for(int j = 1; j < i; j++) {if(a[i] > a[j]) {dp[i] = max(dp[i], dp[j] + a[i]);}}res = max(res, dp[i]);}cout << res << endl;return 0;
}

复杂度分析

时间复杂度为 O ( N 2 ) O(N^2) O(N2)

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

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

相关文章

docker 安装部署nacos

docker 安装nacospull镜像配置mysql挂载运行单机nacos部署。考虑到nacos比较耗费性能&#xff0c;使用docker部署学习。 pull镜像 1.3.1 是github上说明的稳定版本. 至少现在是。 docker pull nacos/nacos-server:1.3.1配置mysql 1. mysql创建nacos_config 数据库2. 数据sq…

ASP.NET(c#)实现重定向的三种方法的总结

(1)Server.Transfer方法: Server.Transfer("m2.aspx");//页面转向(服务器上执行). 服务器停止解析本页,保存此页转向前的数据后,再使页面转向到m2.aspx, 并将转向前数据加上m2.aspx页结果返回给浏览器. (2)Server.Execute方法: Server.Execute("m2.aspx")…

前端学习(1301):gulp建立任务csso和less

const gulp require(gulp); const htmlmin require(gulp-htmlmin); const fileinclude require(gulp-file-include); const less require(gulp-less); gulp.task(first, () > {console.log(第一次执行);});gulp.task(htmlmin, () > {gulp.src(./src/*.html)//压缩去其…

just for rest~

整理了一些可以放昵称的可爱符号&#xff01;ᑋᵉᑊᑊᵒ ᵕ̈ ᑋᵉᑊᑊᵒഒ˙˙₍ᐢ..ᐢ₎˙Ⱉ˙(⌓) ִִ•ᴥ•ଲॱଳॱ————————————ꙫ˙Ꙫ˙&#xff65;◡&#xff65;꒦ິ^꒦ິ•́‸กᵕ᷄≀ ̠˘᷅- ̗̀(ᵔ⌔ᵔ)˙Ⱉ˙˃̶͈ ˂̶͈՞• •՞˙Ⱉ˙҉ง⍢⃝

前端学习(1302):实现es6的转化

const gulp require(gulp); const htmlmin require(gulp-htmlmin); const fileinclude require(gulp-file-include); const less require(gulp-less); const csso require(gulp-csso); const babel require(gulp-babel); gulp.task(first, () > {console.log(第一次执…

EF6 如何判断DataContext有修改,以及如何放弃修改

如何判断DataContext有修改&#xff1a; EF6的 using (var db new Model1()) {if (db.ChangeTracker.HasChanges()){Console.WriteLine("Something has changed");} } EF5中&#xff1a; public bool HasUnsavedChanges(){return this.ChangeTracker.Entries().Any(…

boot整合redis

redisTemplate封装pomredisTemplate配置类redis工具类封装pom <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>redisTemplate配置类 覆盖默认的redis模板…

前端学习(1303):复制文件夹

const gulp require(gulp); const htmlmin require(gulp-htmlmin); const fileinclude require(gulp-file-include); const less require(gulp-less); const csso require(gulp-csso); const babel require(gulp-babel); gulp.task(first, () > {console.log(第一次执…

[另开新坑] 算导v3 #26 最大流 翻译

26 最大流 就像我们可以对一个路网构建一个有向图求最短路一样,我们也可以将一个有向图看成是一个"流量网络(flow network)",用它来回答关于流的问题. Just as we can model a road map as a directed graph in order to find the shortest path from one point to a…

springdata jpa单表操作crud

spring data jpa1. 项目搭建1.1 配置1.2 实体类1.3 继承JpaRepository接口2. 批量新增3. 查询4. 修改 by hql5. 删除 by hql1. 项目搭建 使用boot整合&#xff0c;导入springdata jap, mysql 驱动&#xff0c;lombok&#xff0c;web。 1.1 配置 # boot add jpa, oh~ crud in…

呀~ 一个.java的源文件可以写这么多类啊

1. 外部类 (写在pulic修饰的类外面) 2. 静态内部类(写在类的里面) 3. 局部内部类(写在方法里面) 4. 匿名内部类 5. 函数式接口。lambada表达式。public class LambdaDemo01 {/*** 2. 静态内部类*/static class Love02 implements Lover {Overridepublic void love() {System.ou…

js打开、关闭页面和运行代码那些事

<!doctype html> <html> <head> <meta charset"utf-8"> <meta name"author" content"智能社 - zhinengshe.com"> <meta name"copyright" content"智能社 - zhinengshe.com"> <title…

css定位:相对定位

关于相对定位的结论如下1. 使用相对定位的盒子&#xff0c;会相对于它原来的位置&#xff0c;通过偏移指定的距离&#xff0c;到达新的位置。2.使用相对定位的盒子仍在标准流中&#xff0c;它对父块和兄弟盒子没有任何影响。 <html><head><meta http-equiv”Con…

Vue warn: Invalid prop: type check failed for prop “data“. Expected Array, got Object.

需要数组&#xff0c;但是获取的是对象拉。 但是接口解析处理返回的是数组。 与下面的定义有关。我定义成了对象.png. 正解&#xff1a;

前端学习(1306):node.js模块的加载机制

demo10.js require(./find.js); find.js console.log(找到了); 运行结果

用nodejs 替换文件中所有图片的url

用nodejs 替换文件中所有图片的url 因业务需求&#xff0c;大量文件需要替换url到不同的环境。 所以用nodejs写了这个。本来想用python写&#xff0c;但是大部分同事只有nodejs环境。 主要的命令node rurl.js -new http://www.g.cn/ 替换原有.png .jpg图片图片路劲到 http://ww…

git bash上传大文件到github

git-lfs下载git lfs工具命令GitHub默认最高支持单次上传文件100MB git-lfs&#xff1a;git large file storage 下载git lfs工具 https://git-lfs.github.com/ 命令 在工作目录打开git bash。 # 1. 启用lfsgit lfs install# 2. 要上传的文件&#xff0c;这里指定目录下的…