「模板」最长不下降子序列 LIS
Posted MT默哥的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「模板」最长不下降子序列 LIS相关的知识,希望对你有一定的参考价值。
最长不下降子序列 LIS
在一个数字序列中,找到一个最长的子序列(可以不连续),使得这个子序列是不下降(非递减)的。
例如,现有序列A = 1,2,3,-1,-2,7,9(下标从1开始),它的最长不下降子序列是1,2,3,7,9,长度为5。另外,还有一些子序列是不下降子序列,比如1,2,3,-2,7,9等,但都不是最长的。
输入
第一行为n,表示n个数 第二行n个数
输出
最长不下降子序列的长度
样例
样例输入1
3
1 2 3
样例输出1
3
提示
N小于5000,且每个数\\(\\le max int\\)
Code
dp
#include <bits/stdc++.h>
using namespace std;
int a[5005],dp[5005];
int main()
int n;
cin >> n;
for(int i=1;i<=n;i++)
cin >> a[i];
for(int i=1;i<=n;i++)
dp[i]=1;//一开始就置为1
for(int j=1;j<i;j++)
if(a[j]<=a[i])
//所有可能更新dp[i]的j
if(dp[i]<=dp[j]+1)
dp[i]=dp[j]+1;
int ans=0;
for(int i=1;i<=n;i++)
if(ans<dp[i])
ans=dp[i];
cout << ans;
return 0;
本文来自小默的博客,转载请注明原文链接:https://www.cnblogs.com/momotrace/p/lis-dp.html
动态规划——最长不下降子序列(LIS)
最长不降子序列是这样一个问题:
下面介绍动态规划的做法。
令 dp[i] 表示以 A[i] 结尾的最长不下降序列长度。这样对 A[i] 来说就会有两种可能:
- 如果存在 A[i] 之前的元素 A[j] (j<i),使得 A[j]≤A[i] 且 dp[j]+1>dp[i],那么就把 A[i] 跟在以 A[j] 结尾的 LIS 后面,形成一条更长的不下降子序列(令 dp[i]=dp[j]+1)。
- 如果 A[i] 之前的元素都比 A[i] 大,那么 A[i] 就只好自己形成一条 LIS,但是长度为 1。
由此可以写出状态转移方程:
dp[i] = max{1, dp[j]+1} (j=1,2,....,i-1&&A[j]<A[i])
上面的状态转移方程中隐含了边界:dp[i]=1(1≤i≤n)。显然 dp[i] 只与小于 i 的 j 有关,因此只要让 i 从小到大遍历即可求出整个 dp 数组。然后从整个 dp 数组中找出最大的那个就是要寻求的整个序列的 LIS 长度,整体复杂度为 O(n2)。
代码如下:
1 /* 2 最长不下降子序列 3 */ 4 5 #include <stdio.h> 6 #include <string.h> 7 #include <math.h> 8 #include <stdlib.h> 9 #include <time.h> 10 #include <stdbool.h> 11 12 #define maxn 100 13 int A[maxn], dp[maxn]; 14 15 int main() { 16 int n, i, j; 17 scanf("%d", &n); 18 for(i=1; i<=n; ++i) { // 输入序列 19 scanf("%d", &A[i]); 20 } 21 int ans = -1; // 记录最大的长度 22 for(i=1; i<=n; ++i) { 23 dp[i] = 1; // 初始为仅为自己 24 for(j=1; j<i; ++j) { 25 if(A[i] >= A[j] && (dp[j]+1 > dp[i])) { 26 dp[i] = dp[j] + 1; // 状态转移方程 27 } 28 } 29 if(dp[i] > ans) { 30 ans = dp[i]; // 保存最大值 31 } 32 } 33 printf("%d\\n", ans); 34 35 return 0; 36 }
以上是关于「模板」最长不下降子序列 LIS的主要内容,如果未能解决你的问题,请参考以下文章
1045 Favorite Color Stripe (最长不下降子序列 LIS)