【动态规划】最长上升子序列(LIS)
今天看了《挑战程序设计竞赛》的动态规划部分,感觉对以前一些知其然却不知其所以然的问题有了更好的理解,先整理一部分。
题意:
有一个长为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)的更多相关文章
- 动态规划——最长上升子序列LIS及模板
LIS定义 一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的.对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1 ...
- 算法之动态规划(最长递增子序列——LIS)
最长递增子序列是动态规划中最经典的问题之一,我们从讨论这个问题开始,循序渐进的了解动态规划的相关知识要点. 在一个已知的序列 {a1, a 2,...an}中,取出若干数组成新的序列{ai1, ai ...
- 动态规划 - 最长递增子序列(LIS)
最长递增子序列是动态规划中经典的问题,详细如下: 在一个已知的序列{a1,a2,...,an}中,取出若干数组组成新的序列{ai1,ai2,...,aim},其中下标i1,i2,...,im保持递增, ...
- 动态规划-最长上升子序列(LIS)
时间复杂度为〇(nlogn)的算法,下面就来看看. 我们再举一个例子:有以下序列A[]=3 1 2 6 4 5 10 7,求LIS长度. 我们定义一个B[i]来储存可能的排序序列,len为LIS长度. ...
- 动态规划--最长上升子序列(LIS)的长度
l例如:对于[3,1,4,2,5],最长上升子序列的长度是3 arr = [3,1,4,5,9,2,6,5,0] def lis(arr): #dp[i]表示第i个位置的值为尾的数组的最长递增子序列的 ...
- 动态规划(DP),最长递增子序列(LIS)
题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(d ...
- nlog(n)解动态规划--最长上升子序列(Longest increasing subsequence)
最长上升子序列LIS问题属于动态规划的初级问题,用纯动态规划的方法来求解的时间复杂度是O(n^2).但是如果加上二叉搜索的方法,那么时间复杂度可以降到nlog(n). 具体分析参考:http://b ...
- 2.16 最长递增子序列 LIS
[本文链接] http://www.cnblogs.com/hellogiser/p/dp-of-LIS.html [分析] 思路一:设序列为A,对序列进行排序后得到B,那么A的最长递增子序列LIS就 ...
- 最长回文子序列LCS,最长递增子序列LIS及相互联系
最长公共子序列LCS Lintcode 77. 最长公共子序列 LCS问题是求两个字符串的最长公共子序列 \[ dp[i][j] = \left\{\begin{matrix} & max(d ...
- 最长上升子序列LIS(51nod1134)
1134 最长递增子序列 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递 ...
随机推荐
- 跨库导表数据(sql)
程序员用 列子: insert into "000".tbFreeReportselect ReportCode ,ReportName ,GroupNamefrom openda ...
- 轻松搞定Spring+quartz的定时任务
1.spring 的定时任务写法有两种:一种是继承工作类,一种是普通的Bean,定时写法有两种写法:一种是以时间间隔启动任务SimpleTriggerBean,一种是以时刻启动任务CronTrigge ...
- UVALive 4128 Steam Roller 蒸汽式压路机(最短路,变形) WA中。。。。。
题意: 给一个由n*m个正方形格子组成的矩形,其中每个格子的边都是可以走的,长度给定,规定:如果在进入该路前需要拐弯,或者走完该路需要拐弯,都是需要付出双倍距离的(每条路最多算2倍).问从起点到终点的 ...
- Java多线程编程核心技术---Lock的基本概念和使用
Lock接口: ReentrantLock的基本功能: ReentrantLock的lock和unlock方法进行加锁,解锁.可以起到和synchronized关键字一样的效果: 选择性通知!!!: ...
- 迅为I.MX6DL开发板飞思卡尔Freescale Cortex A9 迅为-iMX6双核核心板
核心板参数 尺寸: 51mm*61mm CPU: Freescale Cortex-A9 双核精简版 i.MX6DL,主频 1.2 GHz 内存: 1GB DDR3 存储: 8GB EMMC 存储 E ...
- codeforces_1065_D.three pieces_思维
题意:一个正方形棋盘,三种棋子,knight:像中国象棋中的马一样走:bishop:斜着走:rook:中国象棋中的车.棋盘中每个格子中标着1--n*n的互不相同的数字,从1开始任选一种棋子开始走,在每 ...
- Mysql基本操作、C++Mysql简单应用、PythonMysql简单应用
MySql基本操作 -- 当指定名称的数据库不存在时创建它并且指定使用的字符集和排序方式 CREATE DATABASE IF NOT EXISTS db_name CHARACTER SET UTF ...
- BASH BUILTIN COMMANDS 内建命令
除非另外说明,这一章介绍的内建命令如果接受 - 引导的选项,那么它也接受 -- 作为参数,来指示选项的结束 : [arguments] 没有效果:这个命令除了扩展 arguments 并且作任何指定的 ...
- lua之链表的实现
-- lua链表的实现 node = {} list = node --初始化,构建一个空表 function init() list.data = --我将头结点的数据域存放链表的长度,以免浪费空间 ...
- Java IO(二)--RandomAccessFile基本使用
RandomAccessFile: 翻译过来就是任意修改文件,可以从文件的任意位置进行修改,迅雷的下载就是通过多个线程同时读取下载文件.例如,把一个文件分为四 部分,四个线程同时下载,最后进行内容拼接 ...