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

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

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

d(i)=max{0,d(j)|j<i,Aj<Ai}+1;

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

考虑这样一个事实,给定两个下标a,b(注意,这里a,b大小未知),如果它们满足Aa<Ab且d(a)==d(b)。则对于所有的i>max{a,b},a并不会比b差。另外,如果b满足Ab<Ai,那么对于a也满足这个性质,且二者的d值相同。但是,如果Aa<Ai,却不一定有Ab<Ai。

通过以上的事实,我们发现,对于某一个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<i),上述的g值也是基于这些状态而改变的。随着i的增大,我们要考虑的状态也越来越多,g也随之发生改变。在给定状态i时,可以用二分查找得到满足g(k)≥Ai的第一个下标k(实际上是要找g(k‘)<Ai的最后一个下标k‘,则d(i)=k‘+1,令k=k‘+1即可得到,这里用lower_bound省略了k‘+1的操作),则d(i)=k,此时Ai<g(k).而d(i)=k,所以更新g(k)=Ai(此时正是利用了上述的事实!虽然这里的g(k)在变小,但仍然大于等于g(k-1),满足上述的不等式)。

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;
}



时间: 2024-10-13 07:52:25

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

动态规划(DP),最长递增子序列(LIS)

题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(dp[k])+1,(k<i),(a[k]<a[i]) #include <stdio.h> #define MAX 1005 int a[MAX];///存数据 int dp[MAX];///dp[i]表示以a[i]为结尾的最长递增子序列(LIS)的长度 int main() { int

poj1836——dp,最长上升子序列(lis)

poj1836——dp,最长上升子序列(lis) Alignment Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 13767   Accepted: 4450 Description In the army, a platoon is composed by n soldiers. During the morning inspection, the soldiers are aligned in a straight

最长上升子序列LIS模板

1 ///最长上升子序列LIS模板 2 int BinSerch(int l,int r,int cut) 3 { 4 while (l<=r) 5 { 6 int m=(l+r)>>1; 7 if (cut>d[m]&&cut<=d[m+1]) return m; 8 if (cut>d[m]) l=m+1; 9 else r=m-1; 10 } 11 return 0; 12 } 13 14 int LIS(int n) 15 { 16 int le

最长上升子序列LIS解法(n^n &amp;&amp; nlogn)

最长递增子序列问题 在一列数中寻找一些数满足 任意两个数a[i]和a[j] 若i<j 必有a[i]<a[j] 这样最长的子序列称为最长递增子序列LIS LIS问题有两种常见的解法 一种时间复杂度n^n 一种时间复杂度nlogn 下面我们先来说一下n^n的算法 设dp[i]表示以i结尾的最长上升子序列的长度 把问题分解 分解成序列中每一项最为终点的最大上升子序列 从第二项开始依次判断 最后找出最大的一项就是答案 则状态转移方程为 dp[i] = max{dp[j]+1}, 1<=j<

动态规划 - 最长递增子序列LIS

问题:一个序列有N个数:A[1],A[2],-,A[N],求出最长非降子序列的长度 样例输入:3 1 2 6 5 4 思路: 首先把问题简单化.可以先求A[1],...A[i]的最长非降子序列,令dp[i]为以A[i]结尾的最长非降子序列.当i = 1 时, 明显是长度dp[1] = 1 : i = 2 时,前面没有比1小的数字,故dp[2]=1 , 此时的最长非降子序列为1 ; i = 3 时,比数字2小的数是1 ,并且只有1 , 分析可知 dp[3] = dp[2]+1:当i = 4 时,找

低价购买 (动态规划,变种最长下降子序列(LIS))

题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它.买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数.你将被给出一段时间内一支股票每天的出售价(216范围内的正整数),你可以选择在哪些天购买这支股票.每次购买都必须遵循“低价购买:再低价购买”的原则.写一个程序计算最大购买次数. 这里是某支股票的价格清单: 日期  1 

[kuangbin带你飞]专题十二 基础DP1 N - Longest Ordered Subsequence POJ - 2533(最长上升子序列LIS)

N - Longest Ordered Subsequence POJ - 2533 题目链接:https://vjudge.net/contest/68966#problem/N 题目: 最长有序子序列如果a1 <a2 <... <aN,则排序ai的数字序列. 让给定数字序列(a1,a2,...,aN)的子序列为任何序列(ai1,ai2,...,aiK),其中1 <= i1 <i2 <... <iK <= N 例如,序列(1,7,3,5,9,4,8)具有有

动态规划算法3——最长上升子序列

今天我们要讲的是最长上升子序列(LIS). [题目描述] 给定N个数,求这N个数的最长上升子序列的长度. [样例输入] 7 2 5 3 4 1 7 6 [样例输出] 4 什么是最长上升子序列? 就是给你一个序列,请你在其中求出一段不断严格上升的部分,它不一定要连续. 就像这样:2,3,4,7和2,3,4,6就是序列2 5 3 4 1 7 6的两种选取方案.最长的长度是4. 那么,怎么求出它的最大上升子序列长度为4呢?这里介绍两种方法,都是以动态规划为基础的. 首先,我们先介绍较慢(O($n^2$

最长上升子序列 (LIS算法(nlong(n)))

设 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] =