码迷,mamicode.com
首页 > 其他好文 > 详细

LIS最长上升子序列

时间:2017-03-11 11:32:17      阅读:163      评论:0      收藏:0      [点我收藏+]

标签:div   注意   turn   printf   main   else   amp   blog   []   

http://cogs.pro/cogs/problem/problem.php?pid=1398

设 A[t]表示序列中的第t个数,F[t]表示从1到t这一段中以t结尾的最长上升子序列的长度,初始时设F [t] = 0(t = 1, 2, ..., len(A))。则有动态规划方程:F[t] = max{1, F[j] + 1} (j = 1, 2, ..., t - 1, 且A[j] < A[t])。 

现在,我们仔细考虑计算F[t]时的情况。假设有两个元素A[x]和A[y],满足 
(1)x < y < t 
(2)A[x] < A[y] < A[t] 
(3)F[x] = F[y] 

 

此时,选择F[x]和选择F[y]都可以得到同样的F[t]值,那么,在最长上升子序列的这个位置中,应该选择A[x]还是应该选择A[y]呢? 

 

很明显,选择A[x]比选择A[y]要好。因为由于条件(2),在A[x+1] ... A[t-1]这一段中,如果存在A[z],A[x] < A[z] < a[y],则与选择A[y]相比,将会得到更长的上升子序列。 
再根据条件(3),我们会得到一个启示:根据F[]的值进行分类。对于F[]的每一个取值k,我们只需要保留满足F[t] = k的所有A[t]中的最小值。设D[k]记录这个值,即D[k] = min{A[t]} (F[t] = k)。 

注意到D[]的两个特点: 
(1) D[k]的值是在整个计算过程中是单调不下降的。 
(2) D[]的值是有序的,即D[1] < D[2] < D[3] < ... < D[n]。 

#include<cstdio>
int d[1050],a[1050]={-1324756};
int main(){
    freopen("lis1.in","r",stdin);
    freopen("lis1.out","w",stdout);
    int i,n,cnt=0,r,l,mid;scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%d",a+i);
        l=1;r=cnt;
        while(l<=r){
            mid=(l+r)>>1;
            if(d[mid]<a[i])l=mid+1;
            else r=mid-1;
        }
        d[l]=a[i];
        if(l>cnt)cnt=l;
    }
    printf("%d",cnt);
    return 0;
}

 

LIS最长上升子序列

标签:div   注意   turn   printf   main   else   amp   blog   []   

原文地址:http://www.cnblogs.com/bennettz/p/6534312.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!