今天看了《挑战程序设计竞赛》的动态规划部分,感觉对以前一些知其然却不知其所以然的问题有了更好的理解,先整理一部分。

题意:

有一个长为n的数列a0,a1,a2,...,an 。请求出这个序列中最长的上升子序列的长度。上升子序列指的是对于任意的i<j都满足ai<aj的子序列。

分析:

设dp[i]为第i个下标之前的子串中最长上升子序列长度。得到递推关系式,时间复杂度O(n2)。

dp[i] = max(dp[i], dp[j] + 1) (a[i] > a[j])

代码:

#include<iostream>
using namespace std;
int a[105], dp[105];
int main (void)
{
int n, ans = 0; cin>>n;
for (int i = 0; i < n; i++) cin>>a[i];
fill(dp, dp + n, 1);
for (int i = 0; i < n; i++){
for (int j = 0; j < i; j++){
if(a[i]>a[j])
dp[i] = max (dp[i], dp[j] + 1);
}
ans = max (dp[i], ans);
}
cout<<ans<<endl;
return 0;
}

分析:

还可以定义dp[i]为长度为i的上升子序列中末尾元素的最小值,对于长度相同的子序列,末尾元素越小,最终获得的上升子序列越可能长。从序列头开始对每个元素a[j]考虑上升子序列长度为0...i的情况,得到递推关系式,时间复杂度O(n2)。

 dp[i] = min(dp[i], a[j]) (a[j]>dp[i-1]||i==1)

代码:

#include<iostream>
using namespace std;
const int INF=0x3fffffff;
int a[105], dp[105];
int main (void)
{
int n, ans = 0; cin>>n;
for (int i = 0; i < n; i++) cin>>a[i];
fill(dp + 1, dp + n + 1, INF);
dp[0] = a[0];
for(int j = 0; j < n; j++){
for(int i = 1; i <= n; i++){
if(i == 1||a[j] > dp[i-1])
dp[i] = min(dp[i], a[j]);
}
}
for(int i = n; i >= 1; i--){
if(dp[i] != INF){
cout<<i<<endl;
break;
}
}
return 0;
}

分析:

上述方法中dp数组除INF外单调递增,所以对于每个元素,最多只更新一次dp数组, 而对于这次更新的位置,不必挨个遍历,可以直接二分查找下界,将复杂度降到O(logn)。

代码:

#include<iostream>
using namespace std;
const int INF=0x3fffffff;
int a[105], dp[105];
int _binary_search(int l, int r, int num)
{
while(l < r){ //区间[l,r)
int mid = l + (r - l)/2;
if(dp[mid] >= num) r = mid;
else l = mid + 1;
}
return l;
}//获取下界
int main (void)
{
int n, ans = 0; cin>>n;
for (int i = 0; i < n; i++) cin>>a[i];
fill(dp + 1, dp + n + 1, INF);
for(int j= 1; j <= n; j++){
int pos = _binary_search(1, n+1, a[j]);
dp[pos] = a[j];
}
for(int i = n; i >= 1; i--){
if(dp[i] != INF){
cout<<i<<endl;
break;
}
}
return 0;
}

分析:

可以直接使用STL中的lower_bound获取下界。通过dp数组中INF的下界获取上升子序列长度。为方便表示可直接定义dp[i]为长度为i+1的上升子序列中末尾元素的最小值。有关 lower_bound 之前写过些简单介绍。

代码:

#include<iostream>
using namespace std;
const int INF=0x3fffffff;
int a[105], dp[105];
int main (void)
{
int n, ans = 0; cin>>n;
fill(dp, dp + n, INF);
for (int i = 0; i < n; i++){
cin>>a[i];
*lower_bound(dp, dp + n, a[i]) = a[i];
}
cout<<lower_bound(dp, dp +n, INF) - dp<<endl;
return 0;
}

【动态规划】最长上升子序列(LIS)的更多相关文章

  1. 动态规划——最长上升子序列LIS及模板

    LIS定义 一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的.对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1 ...

  2. 算法之动态规划(最长递增子序列——LIS)

    最长递增子序列是动态规划中最经典的问题之一,我们从讨论这个问题开始,循序渐进的了解动态规划的相关知识要点. 在一个已知的序列 {a1, a 2,...an}中,取出若干数组成新的序列{ai1, ai ...

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

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

  4. 动态规划-最长上升子序列(LIS)

    时间复杂度为〇(nlogn)的算法,下面就来看看. 我们再举一个例子:有以下序列A[]=3 1 2 6 4 5 10 7,求LIS长度. 我们定义一个B[i]来储存可能的排序序列,len为LIS长度. ...

  5. 动态规划--最长上升子序列(LIS)的长度

    l例如:对于[3,1,4,2,5],最长上升子序列的长度是3 arr = [3,1,4,5,9,2,6,5,0] def lis(arr): #dp[i]表示第i个位置的值为尾的数组的最长递增子序列的 ...

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

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

  7. nlog(n)解动态规划--最长上升子序列(Longest increasing subsequence)

    最长上升子序列LIS问题属于动态规划的初级问题,用纯动态规划的方法来求解的时间复杂度是O(n^2).但是如果加上二叉搜索的方法,那么时间复杂度可以降到nlog(n).  具体分析参考:http://b ...

  8. 2.16 最长递增子序列 LIS

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

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

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

  10. 最长上升子序列LIS(51nod1134)

    1134 最长递增子序列 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递 ...

随机推荐

  1. [BZOJ2190][SDOI2008]仪仗队 数学

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2190 看到这道题首先想到了NOI2010的能量采集,这不就是赤裸裸的弱化版吗?直接上莫比乌 ...

  2. Android开源项目:GifView——Android显示GIF动画

    下载:http://code.google.com/p/gifview/downloads/list 简介:android中现在没有直接显示gif的view,只能通过mediaplay来显示,且还常常 ...

  3. pandas之groupby分组与pivot_table透视表

    zhuanzi: https://blog.csdn.net/qq_33689414/article/details/78973267 pandas之groupby分组与pivot_table透视表 ...

  4. Python学习 Day 7 面向对象 类和实例 访问限制

    面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程 ...

  5. Code::Blocks使用与调试一条龙

    CodeBlocks创建C语言工程版本13.12   选择"create a new project" 选择第四个,点击"go" 4 选择"C&quo ...

  6. JAVA——不简单的fianl关键字

    protected用来修饰 域,代表域的访问权限是:包权限 或者 不同包,但是是子类 : final 修饰常量只要是该常量代入的计算式,在编译时期,就会被执行计算,以减轻运行时的负担.(只对基本数据类 ...

  7. CREATE OPERATOR CLASS - 定义一个新的操作符类

    SYNOPSIS CREATE OPERATOR CLASS name [ DEFAULT ] FOR TYPE data_type USING index_method AS { OPERATOR ...

  8. shellinabox的安装使用

    一.简介 Shell In A Box(发音是shellinabox)是一款基于Web的终端模仿器,由Markus Gutschke开辟而成.它有内置的Web办事器,在指定的端口上作为一个基于Web的 ...

  9. http 1.0 http 1.1 http 2.0的区别

    HTTP/1.0 版的主要缺点是,每个TCP连接只能发送一个请求.发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接. http1.1优点: 1.HTTP 1.1 版引入了持久连接( ...

  10. 大项目之网上书城(七)——书页面以及加入购物车Servlet

    目录 大项目之网上书城(七)--书页面以及加入购物车Servlet 主要改动 1.shu.jsp 代码 效果图 2.shu.js 代码 3.index.jsp 代码 效果图 4.FindBookByC ...