【动态规划专题】最长上升子序列模型
题目 | 算法 |
---|---|
A、AcWing 895. 最长上升子序列 | 模板 |
B、AcWing1017. 怪盗基德的滑翔翼 | 最长上升子序列/最长下降子序列 |
C、AcWing 1014. 登山 | 最长上升子序列/最长下降子序列 |
D、AcWing 482. 合唱队形 | 最长上升子序列 |
E、AcWing 1012. 友好城市 | 思维 |
F、AcWing 1016. 最大上升子序列和 | DP递推 |
目录
- A、AcWing 895. 最长上升子序列(模板)
- B、AcWing1017. 怪盗基德的滑翔翼 (最长上升子序列/最长下降子序列)
- C、AcWing 1014. 登山 (最长上升子序列/最长下降子序列)
- D、AcWing 482. 合唱队形
- E、AcWing 1012. 友好城市
- F、AcWing 1016. 最大上升子序列和
A、AcWing 895. 最长上升子序列(模板)
给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。
今天的最长上升子序列模型的基础
这里是一个O(n2)O(n^ 2)O(n2)的做法。可以用二分优化成O(nlogn)O(nlogn)O(nlogn)
#include <iostream>
#include <algorithm>
#include <cstdio>using namespace std;const int N = 50007, M = 500007, INF = 0x3f3f3f3f;int n,m;
int a[N], f[N];int main(){scanf("%d",&n);for(int i = 1;i <= n;++i){scanf("%d",&a[i]);}for(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);}int res = 0;for(int i = 1;i <= n;++i)res = max(res,f[i]);printf("%d\n",res);return 0;
}
二分优化的O(nlogn)O(nlogn)O(nlogn)
这里直接是拦截导弹的代码,求的是最长不上升子序列(d1,<=)和最长上升子序列(d2, >)
大体的思路就是数组维护一个伪单调栈,每次新的元素如果满足单调性就加入,如果不满足单调性就替换到满足的那一位置,前面的并不删除,只是替换,所以是伪单调栈,最后求最大值即可(主要是替换之后当前的答案也不会改变,但是利用了一个贪心的思想,换完之后可能会更优。因为同样是这么多,我们选更低的肯定后面选择空间会更大,比如当前最大值为300,后面还有两个数,200和250,如果我们到200的时候替换了(此时答案不变),把300替换成200,最后的250就可以取了,答案最优,不然的话250就取不了了)
贴一个解析
#include<iostream>
#include<cstdio>
#include<algorithm>
#define R register
using namespace std;
const int N=100010;
int a[N],d1[N],d2[N],n;
inline bool read(int &x) {char c=getchar();if(c==EOF)return false;while(c>'9'||c<'0')c=getchar();while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();}return true;
}
int main() {while(read(a[++n]));n--;R int len1=1,len2=1;d1[1]=d2[1]=a[1];for(R int i=2; i<=n; i++) {//最长不升子序列if(d1[len1]>=a[i])d1[++len1]=a[i];else *upper_bound(d1+1,d1+1+len1,a[i],greater<int>())=a[i];//最长上升子序列if(d2[len2]<a[i])d2[++len2]=a[i];else *lower_bound(d2+1,d2+1+len2,a[i])=a[i];}printf("%d\n%d",len1,len2);return 0;
}
B、AcWing1017. 怪盗基德的滑翔翼 (最长上升子序列/最长下降子序列)
因为有两种方向,所以我们正向跑一次lcs,逆向跑一次lcs(最长下降子序列),求最大值即可。
#include<iostream>
#include<cstdio>
#include<algorithm>using namespace std;const int N = 500, M = 50007, INF = 0x3f3f3f3f;int n, m;
int t;
int a[N], f[N], g[N];int main(){scanf("%d",&t);while(t -- ){scanf("%d",&n);for(int i = 1;i <= n;++i)scanf("%d",&a[i]);for(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);}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,max(f[i],g[i]));printf("%d\n",res);}return 0;
}
C、AcWing 1014. 登山 (最长上升子序列/最长下降子序列)
本题实际上是求一个最大上升子序列到一个点,然后再以该点为起点求一个最长下降子序列。所以我们可以先预处理出正向的最长上升子序列,再求一个逆向的最长上升子序列(就是最长下降子序列),然后枚举每一个点作为起点,求一个最大值。要注意的是枚举的这个起点被两个子序列算了两次,所以要-1。
#include<iostream>
#include<cstdio>
#include<algorithm>using namespace std;const int N = 1010, M = 50007, INF = 0x3f3f3f3f;int n, m;
int t;
int a[N], f[N], g[N];int main(){scanf("%d",&n);for(int i = 1;i <= n;++i)scanf("%d",&a[i]);for(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);}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);printf("%d\n",res);return 0;
}
D、AcWing 482. 合唱队形
这题和上一道登山几乎一摸一样,只不过求的答案是踢走多少人,所以是n-res
const int N = 1010, M = 50007, INF = 0x3f3f3f3f;
int n, m;
int t;
int a[N], f[N], g[N];int main(){scanf("%d",&n);for(int i = 1;i <= n;++i)scanf("%d",&a[i]);for(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);}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);printf("%d\n",n - res);return 0;
}
E、AcWing 1012. 友好城市
当i>ji>ji>j且i友>j友i_{友}>j_友i友>j友时不交叉
所以可以将南岸从小到大排序 求北岸的最长上升子序列
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>using namespace std;const int N = 5000007, M = 5000007, INF = 0x3f3f3f3f;
typedef pair<int,int> PII;
int n, m;
int b[N];
int f[N];
PII a[N];
int len = 1;
int main(){scanf("%d",&n);for(int i = 1;i <= n;++i){scanf("%d%d",&a[i].first, &a[i].second);}sort(a + 1,a + 1 + n);f[1] = a[1].second;for(int i = 2;i <= n;++i){if(f[len] < a[i].second)f[++len] = a[i].second;else {//int tmp = lower_bound(f + 1, f + 1 + len, a[i].second) - f;//f[tmp] = a[i].second;*lower_bound(f + 1 ,f + 1 + len,a[i].second) = a[i].second;}}printf("%d\n",len);return 0;
}
F、AcWing 1016. 最大上升子序列和
DP问题注意初始化,这里要初始化f[i] = a[i];
很关键。
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 5007, INF = 0x3f3f3f3f;int n, m;
int a[N], f[N];int main(){scanf("%d",&n);for(int i = 1;i <= n;++i)scanf("%d",&a[i]);for(int i = 1;i <= n;++i){f[i] = a[i];for(int j = 1;j < i;++j)if(a[j] < a[i])f[i] = max(f[i],f[j] + a[i]);}int res = 0;for(int i = 1;i <= n;++i)res = max(res,f[i]);printf("%d\n",res);return 0;}
【动态规划专题】最长上升子序列模型相关推荐
- ACwing 895 - 最长上升子序列(最长上升子序列模型)
给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少. 输入格式 第一行包含整数N. 第二行包含N个整数,表示完整序列. 输出格式 输出一个整数,表示最大长度. 数据范围 1 ≤ N ≤ ...
- [AcWing] 1012. 友好城市(C++实现)最长上升子序列模型、较为特殊
[AcWing] 1012. 友好城市(C++实现)最长上升子序列模型 1. 题目 2. 读题(需要重点注意的东西) 3. 解法 4. 可能有帮助的前置习题 5. 所用到的数据结构与算法思想 6. 总 ...
- 动态规划解决最长公共子序列
动态规划解决最长公共子序列 问题描述 给定两个序列,例如 X = "ABCBDAB".Y = "BDCABA",求它们的最长公共子序列的长度. 递归关系 c[i ...
- C++动态规划之最长上升子序列
1 子序列与上升子序列 1.1 子序列 一个序列A={a1,a2,...an}中任意删除若干项,剩余的序列叫做A的一个子序列.例如序列A={1,3,5,4,2},删除其中的第3项和第5项,得到序列B= ...
- 动态规划解最长公共子序列(LCS)(附详细填表过程)
目录 相关概念 子序列形式化定义: 公共子序列定义: 最长公共子序列(以下简称LCS): 方法 蛮力法求解最长公共子序列: 动态规划求解最长公共子序列: 分析规律: 做法: 伪代码: 下面演示下c数组 ...
- javascript写算法(一) 动态规划:最长公共子序列
csdn是疯了吗,右下角的广告是一个人站在猪屁股后面打它...看了一下居然是baidu算出来的广告嵌在了iframe里,fixed to viewport,真是够了.最近还频频出现的广告是一个光头男子 ...
- 最长上升子序列模型 AcWing 1010. 拦截导弹
最长上升子序列模型 AcWing 1010. 拦截导弹 原题链接 AcWing 1010. 拦截导弹 算法标签 DP 线性DP 最长上升子序列 思路 摘自该题解 代码 #include<bits ...
- C++---最长上升子序列模型---导弹防御系统(每日一道算法2023.3.5)
注意事项: 本题的dp:"线性dp-最长上升子序列的长度" 本题的贪心(单调队列):"最长上升子序列模型-拦截导弹" 下面思路只讲如何运用这些东西来解这道题 强 ...
- 动态规划——最长上升子序列模型
最长上升子序列 给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少. 输入格式 第一行包含整数 N. 第二行包含 N 个整数,表示完整序列. 输出格式 输出一个整数,表示最大长度. ...
最新文章
- Okhttp 使用与debug时留的大坑
- Vue入门一、常用的指令
- DPDK — DPDK APP 的指令行参数
- 我非要捅穿这 Neutron(四)Open vSwitch in Neutron
- Linux应用总结(1):自动删除n天前日志
- 【Flutter】Flutter 混合开发 ( Flutter 与 Native 通信 | 在 Flutter 端实现 MethodChannel 通信 )
- Non-interger Area 分类讨论 奇偶 取模 牛客练习赛95
- 5918. 统计字符串中的元音子字符串
- 评论:电商巨头们谁有勇气晒晒“价格战”账单?
- LintCode解题目录
- python文件路径改了需要重新配置环境吗_python自学环境配置
- 老子《道德经》第三章
- 在OpenSSL中添加自定义加密算法
- ADB登录验证暴力破解工具
- 热门的Linux运维管理面板全面汇总
- 扫描域名和扫描IP的区别
- rust服务器显示长度,rust服务器设置倍率
- 百度AI市场MYNT EYE小觅双目摄像机开箱试用全记录
- Altium Designer禁止联网操作说明
- 浅谈几款软件的创新点