最长上升子序列问题
例题
题目描述
给定一个长度为N
的数列,求数值严格单调递增的子序列的长度最长
是多少。
输入格式
第一行包含整数N
。
第二行包含N
个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度
。
数据范围
1
≤
N
≤
1000
1≤N≤1000
1≤N≤1000,
−
1
0
9
≤
数
列
中
的
数
≤
1
0
9
−10^9≤数列中的数≤10^9
−109≤数列中的数≤109
输入样例:
7
3 1 2 1 8 5 6
输出样例:
4
样例解释
输入的序列中最长上升子序列为1,2,5,6
,长度为4
因此输出4.
解题思路
最长上升子序列问题(LIS)也是DP中线性DP的一个模型(其它方法也能做),与背包DP一样,最长上升子序列问题最重要的也是推出状态转移方程
。
状态转移方程
用f[i]
来表示以a[i]
结尾的序列的最长上升子序列长度的最大值
,那么只需要往前面找到所有满足a[i] > a[j]
的j
,然后将当前的f[i]
和f[j] + 1
(表示以a[j]
结尾的最长上升子序列又多了一个a[i]
)取一个max
即可。
i
f
(
a
[
i
]
>
a
[
j
]
)
f
[
i
]
=
m
a
x
(
f
[
i
]
,
f
[
j
]
+
1
)
;
if(a[i] > a[j]) ~~~~~~~f[i] = max(f[i],f[j] + 1);
if(a[i]>a[j]) f[i]=max(f[i],f[j]+1);
代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int n;
int a[N];
int f[N];
int main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++){
f[i] = 1; // 以i结尾的数至少有i一个长度为1的子序列,所以初始化为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]);
cout << res;
return 0;
}