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

摘要:
并且A[j]<A[x]<A[z]<如果A[t]>满足D[j]<A[t]<67组分x=100005;d[mx];=r) 13{14intm=(l+r)>d[m]&=d[m+1])返回m;25d[1]=a[0];d[len])j=++len;30d[j]=a[i];n))39{40for(inti=0;a[i]);LIS(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] = F[y] 

此时,选择F[x]和选择F[y]都可以得到同样的F[t]值,那么,在最长上升子序列的这个位置中,应该选择A[x]还是应该选择A[y]呢? 

很明显,选择A[x]比选择A[y]要好。因为由于条件(2),在A[x+1] ... A[t-1]这一段中,如果存在A[z],A[x] < A[z] < a[y],则与选择A[y]相比,将会得到更长的上升子序列。 
再根据条件(3),我们会得到一个启示:根据F[]的值进行分类。对于F[]的每一个取值k,我们只需要保留满足F[t] = k的所有A[t]中的最小值。设D[k]记录这个值,即D[k] = min{A[t]} (F[t] = k)。 

注意到D[]的两个特点: 
(1) D[k]的值是在整个计算过程中是单调不下降的。 
(2) D[]的值是有序的,即D[1] < D[2] < D[3] < ... < D[n]。 

利 用D[],我们可以得到另外一种计算最长上升子序列长度的方法。设当前已经求出的最长上升子序列长度为len。先判断A[t]与D[len]。若A [t] > D[len],则将A[t]接在D[len]后将得到一个更长的上升子序列,len = len + 1, D[len] = A [t];否则,在D[1]..D[len]中,找到最大的j,满足D[j] < A[t]。令k = j + 1,则有A [t] <= D[k],将A[t]接在D[j]后将得到一个更长的上升子序列,更新D[k] = A[t]。最后,len即为所要求的最长上 升子序列的长度。 

在 上述算法中,若使用朴素的顺序查找在D[1]..D[len]查找,由于共有O(n)个元素需要计算,每次计算时的复杂度是O(n),则整个算法的 时间复杂度为O(n^2),与原来的算法相比没有任何进步。但是由于D[]的特点(2),我们在D[]中查找时,可以使用二分查找高效地完成,则整个算法 的时间复杂度下降为O(nlogn),有了非常显著的提高。需要注意的是,D[]在算法结束后记录的并不是一个符合题意的最长上升子序列!

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 using namespace std;
 6 
 7 const int mx=100005;
 8 int a[mx],d[mx];
 9 
10 int BinSerch(int l,int r,int cut)
11 {
12     while (l<=r)
13     {
14         int m=(l+r)>>1;
15         if (cut>d[m]&&cut<=d[m+1]) return m;
16         if (cut>d[m]) l=m+1;
17         else r=m-1;
18     }
19     return 0;
20 }
21 
22 int LIS(int n)
23 {
24     int len=1,j;
25     d[1]=a[0];
26     for (int i=1;i<n;i++)
27     {
28         if (a[i]>d[len]) j=++len;
29         else j=BinSerch(1,len,a[i])+1;
30         d[j]=a[i];
31     }
32     return len;
33 }
34 
35 int main()
36 {
37     int n;
38     while (~scanf("%d",&n))
39     {
40         for (int i=0;i<n;i++) scanf("%d",&a[i]);
41         printf("%d
",LIS(n));
42     }
43 }

免责声明:文章转载自《最长上升子序列 (LIS算法(nlong(n)))》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇collection动画一个asp.net MVC 的分页代码下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

网上看到的比较全的关于C#操作EXCEL常见操作集合,比较全,写的不错

原文地址:http://hi.baidu.com/kjkj911/blog/item/0ecc3ec7855dd6d4d100600f.html private _Workbook _workBook = null; private Worksheet _workSheet = null; private Excel.Application _excelA...

element-ui 树形表格多选

如题element-ui 2.13.2版本支持树形结构tabel,多层级折叠显示 但是没有多选 + 树形tabel, 业务需求的情况下必须要实现,操作勾选数据编辑 这里我们可以用两个事件来实现:   @select:用户勾选某行触发事件,第一个参数selection:所有选中的数据, 第二参数row:勾选的这行数据)   @select-all : 表头的...

python爬虫(2)——urllib、get和post请求、异常处理、浏览器伪装

urllib基础 urlretrieve() urlretrieve(网址,本地文件存储地址) 直接下载网页到本地 import urllib.request #urlretrieve(网址,本地文件存储地址) 直接下载网页到本地 urllib.request.urlretrieve("http://www.baidu.com","dld.html") u...

利用span设置文字固定宽度

<input type="radio" name="dispMode" value="manul"/><label for="rdoManul"><span class="modeText">手动下载</span></label> <input type=...

1.MyBatis所需要的配置文件

一、Mybatis介绍      MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库...

Entity Framework 6 自定义连接字符串ConnectionString连接MySQL

  在开始介绍之前,首先来看看官方对Entity Framework的解释:Entity Framework (EF) is an object-relational mapper that enables .NET developers to work with relational data using domain-specific objects....