Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 47041 | Accepted: 20905 |
Description
Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
Input
Output
Sample Input
7 1 7 3 5 9 4 8
Sample Output
4
Source
Northeastern Europe 2002, Far-Eastern Subregion
题目大意:求严格递增序列的最大长度。
知识点:
简述:
LIS问题,即最长上升子序列问题,经典的解法有序列DP,通过这个算法,可以获得最长上升子序列的各种详细信息。但是,我们有时候只需要求最长上升子序列的长度,但是o(n^2)的时间复杂度太慢了,我们希望有一种算法,可以更快一点。
算法过程
既然动态规划太慢了,那么自然就想到了贪心。下述算法,就是运用了二分+贪心
首先考虑一个序列a:1、3、2、7、5、6、4 (一共7个数),另外一个辅助数组d,最终序列长度为ans
第1个数:d[1] = a[1] = 1 , ans = 1 ;
第2个数:a[2] > a[1] , 所以d[2] = a[2] , ans = 2 ;
第3个数:d[1] < a[3] < d[2] , 此时ans不改变,但是根据贪心法则,d[2] = a[3] ;
第4个数:a[4] > d[2], d[3] = a[4] = 7 , ans = 3 ;
第5个数:a[5] < d[3] , ans不变,根据贪心法则,d[3] = a[5] ;
第6个数:a[6] > d[4] , d[4] = a[6] , ans =4 ;
第7个数:a[7] < d[4] , 为保证算法完整性,d[3] = a[7] (这里替代的数是第一个大于key的数)。
此时ans=4,d数组为:1、2、4、6 。 (如d[3]=4,意为有个队尾元素为4(最小的序列)的序列使得序列长度为3)
虽然我们算出了答案,但是我们并不能得到最终的最长子序列,这就是这个算法的不足。
再举个例子:1 7 3 5 9 4 8
左边是d数组 右边是数组长度
1 ans=1
1 7 ans=2 比末元素大 那么扩大数组
1 3 ans=2 比末元素小 进去替换比它大的最小元素
1 3 5 ans=3
1 3 5 9 ans=4
1 3 4 9 ans=4
1 3 4 8 ans=4
解题思路:求出ans即可。这个方法速度快,且能求出答案。
代码如下:
#include <cstdio>
int a[1010];
int d[1010];//辅助数组
int ans;//辅助数组长度
int erfen(int x)
{
int l=1,r=ans;//r为d的长度
int mid,pos;//pos是最终找到的那个替换的点
while(l<=r)
{
mid=(l+r)/2;
if(d[mid]>a[x])
{
pos=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
return pos;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
d[1]=a[1];
ans=1;
for(int i=2;i<=n;i++)
{
if(a[i]>d[ans])//比末元素大 那么扩大数组
{
ans++;
d[ans]=a[i];
}
else//比末元素小 进去d数组替换比它大的最小元素,下面用二分来查找速度快
{
d[erfen(i)]=a[i];
}
}
printf("%d\n",ans);
}
return 0;
}