转载来自http://blog.csdn.net/shuangde800/article/details/7474903

很详细啊

hdu 1950 Bridging signals

http://acm.hdu.edu.cn/showproblem.php?pid=1950

===================================
最长上升子序列(LIS)的典型变形,熟悉的n^2的动归会超时。LIS问题可以优化为nlogn的算法。
定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则记录最小的那个最末元素。
注意d中元素是单调递增的,下面要用到这个性质。
首先len = 1,d[1] = a[1],然后对a[i]:若a[i]>d[len],那么len++,d[len] = a[i];
否则,我们要从d[1]到d[len-1]中找到一个j,满足d[j-1]<a[i]<d[j],则根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的)即 d[j] = a[i];
最终答案就是len
利用d的单调性,在查找j的时候可以二分查找,从而时间复杂度为nlogn。
==================================

最长上升子序列nlogn算法

在川大oj上遇到一道题无法用n^2过于是,各种纠结,最后习得nlogn的算法

最长递增子序列,Longest Increasing Subsequence 下面我们简记为 LIS。
排序+LCS算法 以及 DP算法就忽略了,这两个太容易理解了。

假设存在一个序列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)~!

[cpp] view plaincopy
  1. /*
  2. HDU 1950 Bridging signals
  3. -----最长上升子序列nlogn算法
  4. */
  5. #include<cstdio>
  6. #include<cstring>
  7. #define MAXN 40005
  8. int arr[MAXN],ans[MAXN],len;
  9. /*
  10. 二分查找。 注意,这个二分查找是求下界的;  (什么是下界?详情见《算法入门经典》 P145)
  11. 即返回 >= 所查找对象的第一个位置(想想为什么)
  12. 也可以用STL的lowe_bound二分查找求的下界
  13. */
  14. int binary_search(int i){
  15. int left,right,mid;
  16. left=0,right=len;
  17. while(left<right){
  18. mid = left+(right-left)/2;
  19. if(ans[mid]>=arr[i]) right=mid;
  20. else left=mid+1;
  21. }
  22. return left;
  23. }
  24. int main()
  25. {
  26. freopen("input.txt","r",stdin);
  27. int T,p,i,j,k;
  28. scanf("%d",&T);
  29. while(T--){
  30. scanf("%d",&p);
  31. for(i=1; i<=p; ++i)
  32. scanf("%d",&arr[i]);
  33. ans[1] = arr[1];
  34. len=1;
  35. for(i=2; i<=p; ++i){
  36. if(arr[i]>ans[len])
  37. ans[++len]=arr[i];
  38. else{
  39. int pos=binary_search(i);   // 如果用STL: pos=lower_bound(ans,ans+len,arr[i])-ans;
  40. ans[pos] = arr[i];
  41. }
  42. printf("%d\n",len);
  43. }
  44. return 0;
  45. }

最长上升子序列(LIS)长度的O(nlogn)算法 (动态规划)相关推荐

  1. 【训练题】航线设计 | 使用最长上升子序列(LIS)长度的O(nlogn)算法优化

    [问题描述] 有一个国家被一条河划分为南北两部分,在南岸和北岸总共有N对城镇,每一城镇在对岸都有唯一的友好城镇.任何两个城镇都没有相同的友好城镇.每一对友好城镇都希望有一条航线来往.于是他们向政府提出 ...

  2. 最长上升子序列(LIS)长度

    转自:http://www.slyar.com/blog/poj-2533-cpp.html POJ 2533 Longest Ordered Subsequence 属于简单的经典的DP,求最长上升 ...

  3. 最长上升子序列(LIS)长度及其数量

    例题51Nod-1376,一个经典问题,给出一个序列问该序列的LIS以及LIS的数量. 这里我学习了两种解法,思路和代码都是参考这两位大佬的: https://www.cnblogs.com/reve ...

  4. 最长上升子序列(LIS) nlogn解法

    文章目录 经典DP解法O(n^2) dp+二分法(O(nlogn)) 最长上升子序列LIS:Longest increasing subsequence 题目链接:Leetcode300. 最长递增子 ...

  5. 最长上升子序列(LIS)的求法

    最长上升子序列(LIS) 给定一个长度为N的序列A 满足: 1. 1<=x1< x2< x3<-xk<=N 2. A[x1] < A[x2] < A[x3] ...

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

    设 A[t]表示序列中的第t个数,F[t]表示从1到t这一段中以t结尾的最长上升子序列的长度,初始时设F [t] = 0(t = 1, 2, ..., len(A)).则有动态规划方程:F[t] = ...

  7. 最长上升子序列LIS 动态规划 二分查找算法

    所谓LIS表示最长上升子序列,是面试的时候非常容易考察的问题.对于一个序列h1,h2,...hN,其中的子序列hi1,hi2,...hik,满足hi1<hi2<...<hik,那么这 ...

  8. 耐心排序之最长递增子序列(LIS)

    目录 一.问题引入 1.最长递增子序列(LIS) 2.问题分析 3.代码实现 4.问题思考 二.耐心排序 1.基本介绍 2.操作步骤 3.代码实现 三.俄罗斯套娃信封问题 1.题目描述 2.问题分析 ...

  9. 求数组中最长递增子序列的长度

    题目:写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中最长递增子序列的长度. 例:在序列[1, -1, 2, -3, 4, -5, 6, -7]中,其最长递增子序列的长度为4([1, 2, ...

  10. 最长递增子序列的长度(编程之美)

    题目描述: 编程之美2.16中,求数组最长递增子序列的长度,例如数组为:1,-1,2,-3,4,-5,6,-7,那么最长递增序列是:1,2,4,6,长度是4. 可以看出,子序列不一定是连续的 解题思路 ...

最新文章

  1. c语言删除偶数号节点,第十二周作业
  2. php微服务架构设计模式,《微服务架构设计模式》读书笔记---第十一章:开发面向生产环境的微服务应用...
  3. 微信10个实用技巧,值得收藏!
  4. 查询指定目录下的文件中是否包含指定字符串
  5. 怎么把jad反编译放到Eclipse中
  6. Asp.Net MVC5入门学习系列⑥
  7. 电话聊天狂人 (25 分)(map映射 简单做法)
  8. s7200cpu224xp手册_西门子S7-200CPU224XP
  9. ACM的奇计淫巧_输入挂
  10. 126邮箱如何绑定qq邮箱服务器,ecshop使用企业邮箱、qq邮箱和126邮箱如何设置SMTP验证发送邮件...
  11. 电子计算机的基本概念简述
  12. 关注小升初 | 中考分数线刷屏的背后是数千东昌家长学生的泪水
  13. 图扑软件数字孪生汽车生产线,赋能智慧工厂科学运维
  14. 教程:简单十步,在 iTunes 申请 App Store 退款
  15. OpenCV批量读取路径下所有图片
  16. 基于高光谱影像的农作物检测应用简介
  17. 桥接模式和装饰者模式的区别
  18. android加固之后出问题,Android 应用加固
  19. Java BIO的基本介绍
  20. 小白Bert系列-生成pb模型,tfserving加载,flask进行预测

热门文章

  1. 分析器错误 分析器错误信息: 类型“Websystem.Global”不明确: 它可能来自程序集...的解决...
  2. 配置VS2008来Debug .Net框架源码
  3. 三元组顺序表表示的稀疏矩阵加法_知识表示学习记录(1)
  4. python皮卡丘编程代码_Python高级编程-(Part 6 部署代码)
  5. 征信考量社交化和大数据化
  6. CSS样式表初始化杂谈
  7. Mac Brew Uninstall MySql
  8. 学习Unix下C编程的实例
  9. Mysql连接的原理
  10. sqlserver中的循环遍历(普通循环和游标循环)(转载)