动态规划专题小结:最长上升子序列(LIS)问题

(1)问题描述:给定n个整数A1,A2,A3...An。按照从左往右的顺序选择尽可能多的整数,组成一个上升子序列,其中相邻元素不能相等。

(2)解题思路:本题就是经典的最长上升子序列问题(Longest Increasing Subsequence,LIS)。可以通过动态规划解决。定义状态d(i)表示以下标i结尾的LIS的最大长度。那么不难得到如下状态转移方程:

d(i)=max{0,d(j)|j

最终的答案为max{d(i)}。时间复杂度为O(N^2)。由于这种方法十分常见,不予赘述。接下来介绍O(N*logN)的算法。


考虑这样一个事实,给定两个下标a,b(注意,这里a,b大小未知),如果它们满足Aamax{a,b},a并不会比b差。另外,如果b满足Ab

通过以上的事实,我们发现,对于某一个d’值,只要保留最小的那个Aa,使得d(a)==d‘即可。我们用g(i)表示d值为i的最小状态的编号(即i对应的最小的那个Aa,如果不存在设置为INF)。根据以上的推理有如下不等式:

g(1)≤g(2)≤g(3)≤...≤g(n)

注意,上述的g(i)是会动态改变的。对于一个给定的状态i,我们只考虑在i之前已经计算过的状态j(即j

typedef long long ll;
typedef unsigned long long ull;
#define me(s) memset(s,0,sizeof(s))
#define For(i,n) for(int i=0;i<(n);i++)

#define N 100
#define INF 100000000
int a[N];
int g[N];
int d[N];

int main()
{
    freopen("t.txt","r",stdin);
    int n;
    while(~scanf("%d",&n))
    {
        me(a);me(g);me(d);
        fill(g+1,g+n+1,INF);
        For(i,n)
        scanf("%d",&a[i]);
        For(i,n)
        {
            int k=lower_bound(g+1,g+n+1,a[i])-g;
            d[i]=k;
            g[k]=a[i];
        }
        printf("%d\n",d[n-1]);
    }
    return 0;
}




你可能感兴趣的:(算法归纳与总结)