一、概念明确

先来看一串数字:(20,17,19,22,4,7,10,12,5,2,13)

1.序列:像以上排成一列的数字,我们叫它序列,其中每个数字,可以被称为一个元素。

2.子序列:将序列中的部分元素或者全部元素取出后构成的一个新序列,我们称为子序列。

例:将元素  17,22,6,7 取出来构成一个新序列 (17,22,6,7),那么它就是一个子序列

注意:子序列是有序的,不能将后面的元素写在前面。比如写成(22,17,6,7)这种。

3.不下降子序列:不下降的意思是上升或者相同

例:将元素 17,19,22取出来构成一个新序列 (17,19,22),这个序列中的每个元素均大于或等于前一个元素,22大于19,19大于17,因此,我们称这个序列为不下降子序列。再如将元素6,7,10,12,13取出来构成一个新序列(6,7,10,12,13),此序列符合不下降子序列的定义,因此它也是一个不下降子序列

4.最长不下降子序列: 子序列有很多,求出最长不下降子序列的意思是要求出一个子序列,它是不下降的,并且它在所有不下降的子序列中元素最多,这个最长不下降子序列可能有多个。

例:将元素6,7,10,12,13取出来构成一个新序列(6,7,10,12,13),此时它就是一个最长不下降子序列,长度为5。虽然(10,12,13)、(17,19,22)、(2,13)、(5,13)等等都是不下降子序列,但是它们的长度都不是最长的,因此不能称为最长不下降子序列。

二、解题方法

可以利用动态规划进行解题。在利用动态规划进行解题的时候,可以进一步划分为两种思路,分别是从前往后推理从后往前推理。这两种思路都能够求出最长不下降子序列。

1.从前往后推理:依序求出以原序列中各元素分别为子序列结尾情况下能得出的最长不下降子序列

例子:以序列 (11,15,12,13,5,2)为例,通过从前往后推理求出最长不下降子序列的长度

以1号元素为子序列的结尾:此时最长不下降子序列长度为1,因为只有1号元素本身(11)

以2号元素为子序列的结尾:此时最长不下降子序列长度为2,此时包含1号元素和2号元素(11,15)

以3号元素为子序列的结尾:此时最长不下降子序列长度为2,此时包含1号元素和3号元素(11,12)

以4号元素为子序列的结尾:此时最长不下降子序列长度为3,此时包含1、3、4号元素(11,12,13)

以5号元素为子序列的结尾:此时最长不下降子序列长度为1,此时包含5号元素本身(5)

以6号元素为子序列的结尾:此时最长不下降子序列长度为1,此时包含6号元素本身(2)

如下图所示:


2.从后往前推理:依序求出以原序列中各元素分别为子序列起点情况下能得出的最长不下降子序列

以6号元素为子序列的起点:此时最长不下降子序列长度为1,因为只有6号元素本身(2)

以5号元素为子序列的起点:因为以5为起点,后面没有大于等于它的数字,此时最长不下降子序列长度为1,因为只有5号元素本身(5)

以4号元素为子序列的起点:因为以13为起点,后面没有大于等于它的数字,此时最长不下降子序列长度为1,因为只有4号元素本身(13)

以3号元素为子序列的起点:此时最长不下降子序列长度为2,此时包含3、4号元素(12,13)

以2号元素为子序列的起点:此时最长不下降子序列长度为1,后面没有大于等于它的数字,此时最长不下降子序列长度为1,因为只有2号元素本身(15)

以1号元素为子序列的起点:此时最长不下降子序列长度为3,此时包含1、3、4号元素(11,12,13)


3.总结:不管是从前往后推理,还是从后往前推理,都能够求出最长不下降的子序列的长度,其实动态规划就是一个填表的过程,上一个阶段的结果作为求下一个阶段求解的依据。针对这道题目,当我们求出以每个元素为起点或者终点的最长不下降子序列的长度之后,我们还需要找出整个长度行中的最大值,才能找到整个序列的最长不下降子序列长度。

三、代码解题

利用动态规划进行解题,需要找出3个必备条件。

  1. 确定状态
  2. 确定边界
  3. 确定状态转移方程

A.代码1(从前往后推理)

数据结构:

int f[1005];  f[i] 代表以第i号元素为终点最长不下降子序列的长度(确定状态)

int mx = -1; mx用来存放最终最长不下降子序列的长度大小

int data[1005]; data数组用来存放序列数字

输入序列数据和确定边界:

 for(int i=1;i<=n;i++){scanf("%d",&a[i]);f[i]=1;  //确定边界}

其中 ,f[i]数组中的每个元素都需要初始化为1(确定边界),并不是只有f[1]需要初始化为1,其它元素都需要。为什么呢?假设我们只初始化f[1]=1,其它元素不初始化为1,以序列 (11,15,12,13,5,6)为例:

通过观察发现,本来在6号元素位置的长度f[6]应该为2,但是因为没有对f[i]每个元素初始化为1,使得f[6]=1,与我们的期望不符合

核心代码(状态转移方程):

 for(int i=2;i<=n;i++){for(int j=i-1;j>=1;j--){if(a[i]>=a[j])f[i]=max(f[i],f[j]+1);}}

找出f[i[中的最大值,求出最长不下降子序列的长度 

 for(int i=1;i<=n;i++){mx=max(mx,f[i]);}

完整代码 

#include<iostream>
#include<cstdio>
using namespace std;
int n;
int a[1001];
int f[1001];
int mx = -1;
int main() {scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);f[i]=1; }for(int i=2;i<=n;i++){for(int j=i-1;j>=1;j--){if(a[i]>=a[j])f[i]=max(f[i],f[j]+1);}}for(int i=1;i<=n;i++){mx=max(mx,f[i]);}printf("%d",mx);return 0;
}

B.代码2(从后往前推理)

数据结构:

int f[1005];  f[i] 代表以第i号元素为起点最长不下降子序列的长度(确定状态)

int mx = -1; mx用来存放最终最长不下降子序列的长度大小

int data[1005]; data数组用来存放序列数字

输入序列数据和确定边界:

 for(int i=1;i<=n;i++){scanf("%d",&a[i]);f[i]=1;  //确定边界}

其中 ,f[i]数组中的每个元素都需要初始化为1(确定边界),并不是只有f[n]需要初始化为1,其它元素都需要。为什么呢?假设我们只初始化f[n]=1,其它元素不初始化为1,以序列 (11,15,12,13,5,6)为例:

通过观察发现,本来在3号元素位置的长度f[3]应该为2,在1号元素位置的长度f[1]应该为3,但是因为没有对f[i]每个元素初始化为1,使得f[3]=1,f[1]=2,与我们的期望不符合

核心代码(状态转移方程):

 for(int i=n-1;i>=1;i--){for(int j=i+1;j<=n;j++){if(a[i]<=a[j]){f[i]=max(f[i],f[j]+1);}}}

找出f[i[中的最大值,求出最长不下降子序列的长度 

 for(int i=1;i<=n;i++){mx=max(mx,f[i]);}

完整代码 

#include<iostream>
#include<cstdio>
using namespace std;
int n;
int a[1001];
int f[1001]; //以第i项为起点的最长不下降子序列的长度
int mx = -1;
int main() {scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);f[i]=1; }for(int i=n-1;i>=1;i--){for(int j=i+1;j<=n;j++){if(a[i]<=a[j]){f[i]=max(f[i],f[j]+1);}}}for(int i=1;i<=n;i++){mx=max(mx,f[i]);}printf("%d",mx);return 0;
}

四、在线oj测试

写好代码之后,如何验证你写的是否正确呢?可以登录这个OJ,来测试代码的正确性

http://ybt.ssoier.cn:8088/problem_show.php?pid=1281

需要注意的是,该题求的是最长上升子序列,和最长不下降子序列还是有区别的需要稍微修改一下核心代码,上升子序列要求子序列中的元素不可以相同,而最长不下降子序列中的元素可以相同

可以做如下修改:

 //从前往后退for(int i=2;i<=n;i++){for(int j=i-1;j>=1;j--){if(a[i]>a[j])f[i]=max(f[i],f[j]+1);}}//从后往前推for(int i=n-1;i>=1;i--){for(int j=i+1;j<=n;j++){if(a[i]<a[j]){f[i]=max(f[i],f[j]+1);}}}

五、提高拓展

以上只是求出的最长不下降子序列的长度,并没有输出最长不下降子序列中的各个元素,可以花点时间去思考一下怎么才能输出最长不下降子序列中的各个元素?。今天的题解就到这里啦 !如果有任何问题欢迎添加博主微信:Q1313135互相讨论学习。我们下期再见~~~

动态规划之最长不下降子序列相关推荐

  1. 洛谷 - P2766 最长不下降子序列问题(最大流+动态规划+思维建边)

    题目链接:点击查看 题目大意:给出一个由n个数组成的序列,有三个子问题: 求出当前数列的最长不下降子序列的长度len 如果每个数最多只能使用一次,问最多可以组成多少个长度为len的最长不下降子序列 如 ...

  2. 动态规划 最长不下降子序列

    难点 状态:以A[i]结尾的最长不下降子序列 状态转移方程:dp[i] = max(1,dp[j]+1) 代码实现 #include<stdio.h>const int maxn = 10 ...

  3. 最长不下降子序列的O(n^2)算法和O(nlogn)算法

    转帖 最长不下降子序列的O(n^2)算法和O(nlogn)算法 最长不下降子序列(LIS:Longest Increasing Subsequence) //用句通俗的话说,我讲的很通俗易懂~~ 问题 ...

  4. 1045 Favorite Color Stripe(最长不下降子序列)

    1045 Favorite Color Stripe(最长不下降子序列) 题意:按照题目给出的颜色序列找出原颜色序列中对应的子序列,给出的颜色序列不需要在子序列中全部出现. 解法:根据给出的序列对相应 ...

  5. 最长不下降子序列(推广问题)

    最长不下降子序列问题的定义:在一个序列中,找到一个最长的子序列,其中这个序列是非递减的 我们可以把这个非递减推广,其实非递减就是一种顺序,那么我们可以把定义推广到:给出一个顺序序列.目标序列中,在目标 ...

  6. 最大流 ---- 最大不相交路径数 ---- P2766 最长不下降子序列问题(网络流24题)

    题目链接 最多不相交路径 这种问题变化比较多,但都能表示成以下形式: 已知一些路径,每个节点只能属于一条路径,求能选择多少条路径使它们不相交. 主要的方法是拆点,将一个点拆成两个,然后连边,容量表示该 ...

  7. 最长不下降子序列java代码_浅谈最长不下降子序列与最长上升子序列

    唔,最长不下降子序列与最长上升子序列曾是困扰蒟蒻多时的一个问题,应该也有一些人分不清这2个的求法吧. 首先n^2算法肯定是都能分清的,因为不下降和上升的区别是连续的2个能不能相等,只需要在判断的时候判 ...

  8. 【P2766】 最长不下降子序列问题

    题目描述 «问题描述: 给定正整数序列x1,...,xn . (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次 ...

  9. 【动态规划】最长公共上升子序列

    问题 F: [动态规划]最长公共上升子序列 时间限制: 5 Sec  内存限制: 64 MB 提交: 34  解决: 9 [提交] [状态] [命题人:admin] 题目描述 研究发现,大猩猩的基因序 ...

最新文章

  1. 计算机基础及msoffice应用书本,全国计算机等级考试一本通一级计算机基础及MSOffice应用2016年无纸化考试专用...
  2. NLP中的词向量及其应用
  3. 鸿蒙可胜安卓,【鸿蒙币谈】币圈投资中八大见顶信号,让你抓住最佳买卖机会!...
  4. python基础学习(五)第一次修改
  5. office2016打开提示不能加载VBE6EXT.OLB解决方法
  6. (chap4 IP协议) 路由控制表(Routing Table)
  7. ACM入门之【分块习题】
  8. sql中的where 1=1有什么用?
  9. Vue父子组件间的通信
  10. kaggle(04)---avazu_ctr_predictor(baseline)
  11. NodeJS中的require和import
  12. 阿里小二平时和商家交流的时候,明确告知流量喜欢什么样的产品?
  13. input框,需要隐式显示的时候,不让它自动填充的办法
  14. php1怎么获取网卡id号,C#获得MAC地址(网卡序列号)代码
  15. php 网络爬虫开源,phpspider php爬虫框架
  16. 什么是物联网数据采集网关?物联网数据采集网关的特点
  17. 【大数据】Linkis如何安装部署,及一些常见问题
  18. Flutter 混合开发
  19. python 爬虫论_python爬虫——论抓包的正确姿势和学好Javascript的重要性(1)
  20. Windows窗口编程之计算机,WindowsAPI窗口程序设计.docx

热门文章

  1. 初中毕业学计算机那个专业好,初中毕业学哪个计算机专业好
  2. HDU5709 Claris Loves Painting
  3. pycharm安装vim插件
  4. 面试官:今天还是来聊聊CMS垃圾收集器呗?
  5. 龙芯2K1000实战开发-项目整体框架介绍
  6. Java操作文件的方法大全
  7. 【问】已经不用了的门店,在总部如何删除门店库存
  8. JAVA源码学习(一)——String类
  9. QWidget实现手机ipad屏幕滑屏效果
  10. 越来越“default”的微信,愈加精于传播的微信