一个数的序列ai,当a1<a2<...<as的时候,我们称这个序列是上升的。
对于给定一个序列(a1,a2,...,aN),我们可以得到一些上升的子序列(ai1,ai2,...,aik)
这里1<=i1<i2<...ik<=N.比如,对于序列(1,7,3,5,9,4,8),有它的一些上升子序列,如(1,7),
(3,4,8)等等。这些子序列中最长的长度是4,比如子序列(1,3,5,8)
求对于给定的序列,求出最长上升子序列的长度。
输入数据
输入的第一行是序列的长度N(1<=N<=1000).
第二行给出序列中的N个整数,这些整数的取值范围都在0到10000.
输出要求
最长上升子序列的长度
输入样例
7
1 7 3 5 9 4 8
输出样例
4
解题思路
maxLen(k)表示以ak作为"终点"的最长上升子序列的长度那么:
初始状态:maxLen(1)=1
maxLen(k)=max{maxLen(i):1<=i<k且ai<ak且k!=1}+1
maxLen(k)的值,就是在ak的左边,"终点"数值小于ak,且长度大的那个上升子序列再加1.
因为ak左边任何"终点"小ak的子序列,加上ak后就能形成一个更长的上升子序列。
动归的常用两种形式
1)递归型
优点:直观,容易编写
缺点:可能会因为递归层数太深导致爆栈,函数调用带来额外时间开销。
无法使用滚动数组节省空间。总体来说,比递推型慢。
2)递推型
效率高,有可能使用滚动数组节省空间。
/**
* "人人为我"递推型动归程序
*/
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX = 10010;
//原数组
int a[MAX];
//最长子序列问题
int maxLen[MAX];
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
maxLen[i] = 1;
}
//从第二个元素开始求最长上升子序列
for (int i = 2; i <= n; i++)
{
//对于每个元素求它的最长上升子序列
for (int j = 1; j < i; j++)
{
if (a[j] < a[i])
maxLen[i] = max(maxLen[i], maxLen[j] + 1);
}
}
/*
for(int j=1;j<=n;j++){
cout<<maxLen[j]<<" ";
}
*/
//输出maxLen中最大元素值
cout << *max_element(maxLen+1, maxLen + n+1 );
return 0;
}