有关概念:
最长上升子序列(LIS,Longest Increasing Subsequence),在一个序列中最长的单调递增的子序列
思路:
求LIS通常有O(n2)和O(nlogn)两种算法
(1)O(n2)算法
fi表示以第i个数结尾的LIS长度
对于序列中的一个数i,在i前面枚举数j,j满足比i小且fj最大,将i作为j的后继
伪代码&状态转移方程:
f1=1
for i=2...n
for j=1...i-1
if(aj<ai)fi=max(fi,fj+1)
最后结果在f1~fn中取最大值
当然,可以在更新fi的时候顺便记录j的位置,在最后可以输出整个LIS
1 #include<cstdio> 2 #define MAXN 3 int n,a[MAXN],f[MAXN],ans; 4 inline int max(int x,int y) 5 { 6 return x>y?x:y; 7 } 8 int main() 9 { 10 scanf("%d",&n); 11 for(int i=1;i<=n;++i) 12 { 13 scanf("%d",&a[i]); 14 f[i]=1; 15 } 16 for(int i=2;i<=n;++i) 17 for(int j=1;j<i;++j) 18 if(a[i]>=a[j]&&f[j]+1>=f[i])f[i]=f[j]+1; 19 for(int i=1;i<=n;++i)ans=max(ans,f[i]); 20 printf("%d",ans); 21 return 0; 22 }
(2)O(nlogn)算法
fi表示长度为i的非降子序列的最小末尾,len记录当前最长的非降子序列长度
可得f1<=f2<=f3<=...<=fmaxlen
每次读入一个数字k,先与flen比较,如果大于则添加至f++len,作为原来flen的后继
否则在f中找到fi<k<=fi+1,更新为fi+1为k,即k比原来fi+1更优,可作为fi的后继
最后输出len即可
然而查找过程可以用二分优化,就得出这种算法
(样例推导见大犇博客http://www.cnblogs.com/ziyi--caolu/p/3227121.html)
1 #include<cstdio> 2 #define MAXN 3 int n,s[MAXN],f[MAXN],len; 4 int main() 5 { 6 scanf("%d",&n); 7 scanf("%d",&s[1]); 8 f[1]=s[1]; 9 for(int i=2;i<=n;++i) 10 { 11 scanf("%d",&s[i]); 12 if(s[i]>f[len])f[++len]=s[i]; 13 else 14 { 15 int l=1,r=len; 16 while(l<r) 17 { 18 int mid=(l+r)>>1; 19 if(s[i]>f[mid])l=mid+1; 20 else r=mid; 21 } 22 f[l]=s[i]; 23 } 24 } 25 printf("%d",len); 26 return 0; 27 }
时间: 2024-11-10 01:28:10