最长上升子序列(LIS)动态规划
最长上升子序列
给你n个整数 A1 A2 ········· An 找出在这个数组里面的最长上升的子序列。例如给你(1,7,3,5,9,4,8),他的上升子序列有(1,7) (3,4,8)等等之类的,但是最长的上升子序列是(1,3,5,8)。
1)n^2算法
dp[i] 为当前数组里第i个元素时,以a[i]元素为结尾的最长子序列长度。
动态转移方程是:dp[i] = max ( dp[i] , dp[j] + 1 ) 其中 j<i 且 a[j] < a[i] 。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <sstream>
#include <algorithm>
using namespace std;
#define pb push_back
#define mp make_pair
#define ms(a, b) memset((a), (b), sizeof(a))
//#define LOCAL
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int maxn = +;
const LL mod = +;
int a[maxn];
int dp[maxn];
int main()
{
#ifdef LOCAL
freopen("input.txt" , "r", stdin);
#endif // LOCAL
int n;
scanf("%d", &n);
for(int i=;i<n;i++) scanf("%d", &a[i]);
dp[]=;
for(int i=;i<n;i++)
{
dp[i] = ;
for(int j=;j<i;j++)
{
if(a[j]<a[i] && dp[j]+ > dp[i])
dp[i] = dp[j] + ;
}
}
int ans = ;
for(int i=;i<n;i++) ans = max(ans, dp[i]);
printf("%d\n", ans);
return ;
}
2)nlogn算法
假设存在一个序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5。n
下面一步一步试着找出它。
我们定义一个序列B,然后令 i = 1 to 9 逐个考察这个序列。
此外,我们用一个变量Len来记录现在最长算到多少了
首先,把d[1]有序地放到B里,令B[1] = 2,就是说当只有1一个数字2的时候,长度为1的LIS的最小末尾是2。这时Len=1
然后,把d[2]有序地放到B里,令B[1] = 1,就是说长度为1的LIS的最小末尾是1,d[1]=2已经没用了,很容易理解吧。这时Len=1
接着,d[3] = 5,d[3]>B[1],所以令B[1+1]=B[2]=d[3]=5,就是说长度为2的LIS的最小末尾是5,很容易理解吧。这时候B[1..2] = 1, 5,Len=2
再来,d[4] = 3,它正好加在1,5之间,放在1的位置显然不合适,因为1小于3,长度为1的LIS最小末尾应该是1,这样很容易推知,长度为2的LIS最小末尾是3,于是可以把5淘汰掉,这时候B[1..2] = 1, 3,Len = 2
继续,d[5] = 6,它在3后面,因为B[2] = 3, 而6在3后面,于是很容易可以推知B[3] = 6, 这时B[1..3] = 1, 3, 6,还是很容易理解吧? Len = 3 了噢。
第6个, d[6] = 4,你看它在3和6之间,于是我们就可以把6替换掉,得到B[3] = 4。B[1..3] = 1, 3, 4, Len继续等于3
第7个, d[7] = 8,它很大,比4大,嗯。于是B[4] = 8。Len变成4了
第8个, d[8] = 9,得到B[5] = 9,嗯。Len继续增大,到5了。
最后一个, d[9] = 7,它在B[3] = 4和B[4] = 8之间,所以我们知道,最新的B[4] =7,B[1..5] = 1, 3, 4, 7, 9,Len = 5。
于是我们知道了LIS的长度为5。
!!!!! 注意。这个1,3,4,7,9不是LIS,它只是存储的对应长度LIS的最小末尾。有了这个末尾,我们就可以一个一个地插入数据。虽然最后一个d[9] = 7更新进去对于这组数据没有什么意义,但是如果后面再出现两个数字 8 和 9,那么就可以把8更新到d[5], 9更新到d[6],得出LIS的长度为6。
然后应该发现一件事情了:在B中插入数据是有序的,而且是进行替换而不需要挪动——也就是说,我们可以使用二分查找,将每一个数字的插入时间优化到O(logN)~~~~~于是算法的时间复杂度就降低到了O(NlogN)~!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <sstream>
#include <algorithm>
using namespace std;
#define pb push_back
#define mp make_pair
#define ms(a, b) memset((a), (b), sizeof(a))
//#define LOCAL
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int maxn = +;
const LL mod = +;
int a[maxn];
int dp[maxn];
int Binary_search(int key, int len)
{
int l=, r=len+;
while(l<r)
{
int middle = (l+r) >> ;
if(key>=dp[middle])
l = middle +;
else
r = middle;
}
return l;
}
int main()
{
#ifdef LOCAL
freopen("input.txt" , "r", stdin);
#endif // LOCAL
int n, len;
scanf("%d", &n);
for(int i=;i<n;i++) scanf("%d", &a[i]);
dp[] = a[];
len = ;
for(int i=;i<n;i++)
{
if(a[i] > dp[len])
dp[++len] = a[i];
else{
int j = Binary_search(a[i], len);
dp[j] = a[i];
}
}
printf("%d\n", len);
return ;
}
附上一些练习题:
1)https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1134
2)http://poj.org/problem?id=2533
3)http://poj.org/problem?id=1631
4)http://poj.org/problem?id=1887(最长不上升子序列)
5)http://poj.org/problem?id=1609(最长不上升子序列)
这些题的题解稍后放出。
最长上升子序列(LIS)动态规划的更多相关文章
- 算法之动态规划(最长递增子序列——LIS)
最长递增子序列是动态规划中最经典的问题之一,我们从讨论这个问题开始,循序渐进的了解动态规划的相关知识要点. 在一个已知的序列 {a1, a 2,...an}中,取出若干数组成新的序列{ai1, ai ...
- 动态规划 - 最长递增子序列(LIS)
最长递增子序列是动态规划中经典的问题,详细如下: 在一个已知的序列{a1,a2,...,an}中,取出若干数组组成新的序列{ai1,ai2,...,aim},其中下标i1,i2,...,im保持递增, ...
- 动态规划(DP),最长递增子序列(LIS)
题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(d ...
- 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 ...
- 2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组)
2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组) https://www.luogu.com.cn/problem/P2516 题意: 给定字符串 \(S\) ...
- CJOJ 2044 【一本通】最长公共子序列(动态规划)
CJOJ 2044 [一本通]最长公共子序列(动态规划) Description 一个给定序列的子序列是在该序列中删去若干元素后得到的序列.确切地说,若给定序列X,则另一序列Z是X的子序列是指存在一个 ...
- 最长上升子序列LIS(51nod1134)
1134 最长递增子序列 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递 ...
- 【BZOJ2423】最长公共子序列(动态规划)
[BZOJ2423]最长公共子序列(动态规划) 题面 BZOJ 洛谷 题解 今天考试的时候,神仙出题人\(fdf\)把这道题目作为一个二合一出了出来,我除了orz还是只会orz. 对于如何\(O(n^ ...
- 51nod 最长单增子序列(动态规划)
最长单增子序列 (LIS Longest Increasing Subsequence)给定一个数列,从中删掉任意若干项剩余的序列叫做它的一个子序列,求它的最长的子序列,满足子序列中的元素是单调递增的 ...
随机推荐
- SSM001/构建maven多模块项目
一.Idea构建maven多模块项目 1.创建maven项目--创建父模块 [1].File->New->Module... [2].点击next,填写:GroupId,ArtifactI ...
- C#后台保存Cookie
一般是: Response.Cookies["backurl"].Expires.AddDays(2); 但是,IE浏览器保存Cookie用 Response.Cookies[&q ...
- python 安装成windows服务
参考文档 https://blog.csdn.net/kongxx/article/details/65435076 https://www.cnblogs.com/lishuai0214/artic ...
- MySQL binlog之数据恢复
一.恢复方案1.数据量不是特别大,可以将mysqldump命令备份的数据使用mysql客户端命令或者source命令完成数据的恢复:2.使用Xtrabackup完成数据库的物理备份恢复,期间需要重启数 ...
- 3.Golang的包导入
1.golang的源码文件可以随意命名,但是属于同一个包的源文件必须声明 package base 2.golang的包引入规则 import ( "fmt" #系统包直接写名字 ...
- Reactjs 列表优化的一些心得
前言 在应用开发中,列表是我们使用频率非常高的一种展现形式,在reactjs项目中更是如此.无处不在的使用更是需要我们小心触发性能瓶颈的深水炸弹. 下面就我最近的总结出的几点心得分享给大家,有什么问题 ...
- mysql的sql语句优化方法面试题总结
mysql的sql语句优化方法面试题总结 不要写一些没有意义的查询,如需要生成一个空表结构: select col1,col2 into #t from t where 1=0 这类代码不会返回任何结 ...
- HTML导航框架实现
导航栏界面(html_contents.html) <!DOCTYPE html> <html> <head> <meta charset=” utf-8” ...
- sqoop使用中文手册
文章转载自:http://www.zihou.me/html/2014/01/28/9114.html 1. 概述 本文档主要对SQOOP的使用进行了说明,参考内容主要来自于Cloudera ...
- iOS App中 使用 OpenSSL 库
转自:http://blog.csdn.net/kmyhy/article/details/6534067 在你的 iOS App中 使用 OpenSSL 库 ——译自x2on的“Tutorial: ...