总时间限制: 2000ms 内存限制: 65536kB
描述
一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的。对于给定的一个序列(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
来源
翻译自 Northeastern Europe 2002, Far-Eastern Subregion 的比赛试题
下面介绍2种思路:
思路一:状态定义为以i为开头或结尾的最长上升子序列的长度
写法1:状态定义为以i为开头的最长上升子序列的长度(原作者:Trigger_G,按本作者的编程习惯略微改动,侵删)
内存:248kB 时间:12ms
/*作者:Trigger_G*/
/*written by Trigger_G*/
/*来自网站:https://blog.csdn.net/qq_36006682/article/details/102755984*/
#include<bits/stdc++.h>
using namespace std;
int a[1001],b[1001];
int maxx=0,point,n;
int main()
{
cin>>n;
for(int p=1;p<=n;p++)b[p]=1;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=n-1;i>=1;i--)for(int j=i;j<=n;j++)if(a[i]<a[j]&&b[i]<=b[j])b[i]=b[j]+1;
for(int i=1;i<=n;i++)if(b[i]>maxx)maxx=b[i];
cout<<maxx;
return 0;
}
写法2:状态定义为以i为结尾的最长上升子序列的长度(原创)
内存:276kB 时间:8ms
/*作者:宇宙猎手*/
/*written by Yu Zhou Hunter*/
#include<bits/stdc++.h>
using namespace std;
int a[1000],b[1000],m,n;
int main()
{
cin>>m;
for(int i=0;i<m;i++)
{
cin>>a[i];
for(int j=0;j<i;j++)if(a[i]>a[j]&&b[i]<=b[j])b[i]=b[j]+1;
if(b[i]>n)n=b[i];
}
cout<<n+1;
return 0;
}
思路二:贪心算法(原作者:君义_noip,按本作者的编程习惯略微改动,侵删)
内存:280kB 时间:10ms
/*作者:君义_noip*/
/*written by 君义_noip*/
/*来自网站:https://blog.csdn.net/lq1990717/article/details/124136872*/
#include<bits/stdc++.h>
using namespace std;
int n,a[1001],d[1001],len;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
len++;
d[len]=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]>d[len])len++,d[len]=a[i];
else
{
int l=1,r=len;
while(l<r)
{
int m=(l+r)/2;
if(d[m]>=a[i])r=m;
else l=m+1;
}
d[l]=a[i];
}
}
cout<<len;
return 0;
}
已访问过其它网站,解法与此大同小异。
若有新解法,欢迎在评论区讨论。