最长递增子序列是动态规划中最经典的问题之一,我们从讨论这个问题开始,循序渐进的了解动态规划的相关知识要点。

在一个已知的序列 {a1, a 2,...an}中,取出若干数组成新的序列{ai1, ai 2,...aim},其中下标 i1、i2…im保持递增,即新数列中的各个数之间依旧保持原数列中的先后顺序,那么我们称新的序列{ai1, ai 2,...aim}为原序列的一个子序列。若在子序列中,当下标 ix > iy时,aix > aiy,那么我们称这个子序列为原序列的一个递增子序列。最长递增子序列问题,就是在一个给定的原序列中,求得其最长递增子序列长度。

有序列 {a1, a 2,...an},我们求其最长递增子序列长度。按照递推求解的思想,我们用 F[i]代表若递增子序列以 ai结束时它的最长长度。当i较小,我们容易直接得出其值,如 F[1] = 1。那么,如何由已经求得的 F[i]值推得后面的值呢?假设,F[1]到 F[x-1]的值都已经确定,注意到,以ax结尾的递增子序列,除了长度为1的情况,其它情况中,ax都是紧跟在一个由 ai(i<x)组成递增子序列之后。要求以ax结尾的最长递增子序列长度,我们依次比较ax与其之前所有的 ai(i<x),若ai小于ax,则说明ax可以跟在以ai结尾的递增子序列之后,形成一个新的递增子序列。又因为以ai结尾的递增子序列最长长度已经求得,那么在这种情况下,由以ai结尾的最长递增子序列再加上ax得到的新的序列,其长度也可以确定,取所有这些长度的最大值,我们即能得到 F[x]的值。特殊的,当没有ai(i<x)小于 ax,那么以ax结尾的递增子序列最长长度为1。

F[ x] = max{1, F[i] + 1 | ai < ax & &i < x};

我们给出求序列{1,4,3,2,6,5}的最长递增子序列长度的所有 F[i]供读者参考。

F[1](1)

F[2](4)

F[3](3)

F[4](2)

F[5](6)

F[6](5)

1

2

2

2

3

3

总结一下,求最长递增子序列的递推公式为:

F[1] = 1;

F[i] = max{1, F[ j] + 1 | aj < ai & & j < i};

接下来是一个应用的列子,我们通过这个列子,来再度深入的了解下LIS。

某国为了防御敌国的导弹袭击,发展中一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于等于前一发的高度。某天,雷达捕捉到敌国导弹来袭。由于该系统还在试用阶段,所以只用一套系统,因此有可能不能拦截所有的导弹。

输入:
第一行输入测试数据组数N(1<=N<=10)
接下来一行输入这组测试数据共有多少个导弹m(1<=m<=20)
接下来行输入导弹依次飞来的高度,所有高度值均是大于0的正整数。
输出:
输出最多能拦截的导弹数目
样例输入:
2
8
389 207 155 300 299 170 158 65
3
88 34 65
样例输出:
6
2
#include <stdio.h>
int max(int a,int b) {return a > b ? a : b;} //取最大值函数
int list[26]; //按袭击事件顺序保存各导弹高度
int dp[26]; //dp[i]保存以第i个导弹结尾的最长不增子序列长度
int main() {
int n;
while (scanf("%d",&n) != EOF) {
for (int i = 1;i <= n;i ++) {
scanf("%d",&list[i]);
} //输入
for (int i = 1;i <= n;i ++) { //按照袭击时间顺序确定每一个dp[i]
int tmax = 1; //最大值的初始值为1,即以其结尾的最长不增子序列长度至少为1
for (int j = 1;j < i;j ++) { //遍历其前所有导弹高度
if (list[j] >= list[i]) { //若j号导弹不比当前导弹低
tmax = max(tmax,dp[j] + 1); //将当前导弹排列在以j号导弹结尾的最长不增子序列之后,计算其长度dp[j] + 1,若大于当前最大值,则更新最大值
}
}
dp[i] = tmax; //将dp[i]保存为最大值
}
int ans = 1;
for (int i = 1;i <= n;i ++) {
ans = max(ans,dp[i]);
} //找到以每一个元素结尾的最长不增子序列中的最大值,该最大值即为答案
printf("%d\n",ans); //输出
}
return 0;
}  

最长递增子序列问题,是我们接触的第一个真正意义上的动态规划问题。我们来回顾它的特点。首先,我们将这个问题分割成许多子问题,每个子问题为确定以第 i个数字结束的递增子序列最长长度。其次,这些子问题之间存在某种联系,以任意一个数字结束的递增子序列长度,与以排在该数字之前所有比它小的元素结尾的最长递增子序列长度有关,且仅与其数字量有关,而与其具体排列无关。


 

 

 

 

算法之动态规划(最长递增子序列——LIS)的更多相关文章

  1. 动态规划 - 最长递增子序列(LIS)

    最长递增子序列是动态规划中经典的问题,详细如下: 在一个已知的序列{a1,a2,...,an}中,取出若干数组组成新的序列{ai1,ai2,...,aim},其中下标i1,i2,...,im保持递增, ...

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

    题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(d ...

  3. 最长回文子序列LCS,最长递增子序列LIS及相互联系

    最长公共子序列LCS Lintcode 77. 最长公共子序列 LCS问题是求两个字符串的最长公共子序列 \[ dp[i][j] = \left\{\begin{matrix} & max(d ...

  4. 2.16 最长递增子序列 LIS

    [本文链接] http://www.cnblogs.com/hellogiser/p/dp-of-LIS.html [分析] 思路一:设序列为A,对序列进行排序后得到B,那么A的最长递增子序列LIS就 ...

  5. 一个数组求其最长递增子序列(LIS)

    一个数组求其最长递增子序列(LIS) 例如数组{3, 1, 4, 2, 3, 9, 4, 6}的LIS是{1, 2, 3, 4, 6},长度为5,假设数组长度为N,求数组的LIS的长度, 需要一个额外 ...

  6. 动态规划----最长递增子序列问题(LIS)

    题目: 输出最长递增子序列的长度,如输入 4 2 3 1 5 6,输出 4 (因为 2 3 5 6组成了最长递增子序列). 暴力破解法:这种方法很简单,两层for循环搞定,时间复杂度是O(N2). 动 ...

  7. 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现

    关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已 ...

  8. 最长递增子序列LIS再谈

    DP模型: d(i) 以第 i 个元素结尾的最长递增子序列的长度. 那么就有 d(i) = max(d(j)) + 1;(j<i&&a[j]<a[i]),答案 max(d( ...

  9. 算法面试题 之 最长递增子序列 LIS

    找出最长递增序列 O(NlogN)(不一定连续!) 参考 http://www.felix021.com/blog/read.php?1587%E5%8F%AF%E6%98%AF%E8%BF%9E%E ...

随机推荐

  1. Android开发工具

    Android开发工具: AndroidDevTools: 收集整理Android开发所需的Android SDK.开发中用到的工具.Android开发教程.Android设计规范,免费的设计素材等. ...

  2. DataRow 数组转化成DataTable

    #region 封装DataTable DataTable dt = null; if (newRows.Length > 0) { dt = newRows[0].Table.Clone(); ...

  3. 常用 ARM 指令集及汇编

    ARM7TDMI(-S)指令集及汇编 ARM 处理器是基于精简指令集计算机(RISC)原理设计的,指令集和相关译码机制 较为简单,ARM7TDMI(-S)具有 32 位 ARM 指令集和 16 位 T ...

  4. OpenCV 64位时 应用程序无法正常启动0x000007b 问题解决

    这问题根本不是DirectX问题,不知道网上怎么这么这样的回复.而且也不亲自验证一下.下面将自己花很多时间才解决的方式整理一下. 因为一般情况下你配置的OpenCV加入系统环境变量的都是X86下的bi ...

  5. Mac的文件比对工具:Meld、Beyond Compare

    Meld开源免费 Beyond Compare可以在Windows.Mac下使用,但是收费,需要自己破解

  6. adb logcat通过包名过滤(dos命令find后跟变量)

    adb命令中似乎没有直接通过报名来过滤的功能,可是能够通过过滤进程的pid来过滤该应用的日志 过滤条件:该app在执行 实现原理: 1.获取该app执行时的pid 2.通过find命令,过滤pid的日 ...

  7. Linux、CentOS系统下调整home和根分区大小

    1.首先查看磁盘使用情况 [root@localhost ~]# df -h 文件系统 容量 已用 可用 已用% 挂载点 Filesystem Size Used Avail Use% Mounted ...

  8. 使用webpack构建本地服务器

    想不想让你的浏览器监听你的代码的修改,并自动刷新显示修改后的结果,其实Webpack提供一个可选的本地开发服务器,这个本地服务器基于node.js构建,可以实现你想要的这些功能,不过它是一个单独的组件 ...

  9. Spark(十二) -- Spark On Yarn & Spark as a Service & Spark On Tachyon

    Spark On Yarn: 从0.6.0版本其,就可以在在Yarn上运行Spark 通过Yarn进行统一的资源管理和调度 进而可以实现不止Spark,多种处理框架并存工作的场景 部署Spark On ...

  10. JavaScript basics: 2 ways to get child elements with JavaScript

    原文: https://blog.mrfrontend.org/2017/10/2-ways-get-child-elements-javascript/ Along the lines of oth ...