主演思想:
遍历之前的所有数并继承他前面的上升长度最长的并且比他小那个数的序列长度,并加一
代码:
# include <cstdio>
# include <iostream>
# include <cstring>
# define MAX 1000
using namespace std;
int s[MAX + 10];//s数组保存序列
int slen [MAX + 10];// 保存以i为终点的最长上升子序列的长度
int n, ml = 0;
int main ()
{
cin >> n;
memset (slen , 1, sizeof (slen)); //本身那个数也包含进去
for (int i=0; i<n; ++i)
cin >> s[i];
for (int i=0; i<n; ++i)
{
int m = 0;
for (int j=0; j<i; ++j)
{
if (s[j] < s[i] && slen[i] > m)
m = slen[j]; //m 存放i之前的最长子序列的长度,并不包括i
}
slen[i] = m + 1;//讲i自身加上
if (slen[i] > ml)
ml = slen[i];//ml是目前为止最长子序列的长度
}
cout << ml << endl;
return 0;
}
另一种解法动态规划, 摘自挑战程序设计竞赛
int n;
int a[MAX], dp[MAX];
void solve ()
{
int res = 0;
for (int i=0; i<n; ++i)
{
dp[i] = 1;
for (int j=0; i<i; ++j)
if (a[i] > a[j])
dp[i] = max (dp[i], dp[j] + 1);
res = max (res, dp[i]);
}
printf ("%d\n", res);
}
首先dp数列中除了inf之外全是单调递增的,所以可以知道对于每个a最多只需要一次更新。对于这次更新究竟在什么位置,不必逐个遍历, 可以用二分搜索,这样就可以在O(nlogn)时间内求出结果。
int dp[MAX];
void solve ()
{
fill (dp, dp+n, INF);
for (int =0; i<n; ++i)
{
*lower_bound (dp, dp+n,a[i]) = a[i];
}
printf ("%d\n", lower_bound (dp, dp+n, INF)-fp);
}