动态规划基础之最长上升子序列(LIS)

最长上升子序列又名最长不下降子序列,英文名Longest Increasing Subsequence(简称LIS)

What is LIS?

首先介绍一下子序列吧。子序列就是一组数据中的一些数据组成的序列(说实话我也解释不清QAQ!!)

举个栗子吧:

我们有一组数据:21  56  13  57  96  31  52

那么,21  13 96是它的子序列;56  13  96  52也是它的子序列

就是说只要保证原数据的顺序不变,子序列中的数据在原数据中不一定要相邻。

那么,上升子序列又是什么呢?

顾名思义,上升嘛,就是从小到大排列。

像我举的例子中的一组上升子序列是:21  56  57  96

这样你们明白了吗?


现在给出了数据的长度n,并且给出了具体数据,让你求它的最长的上升子序列的长度是多少。

也许会有多个解,但是题目只要求你求出长度,那么这个多解就没必要考虑了。

如果没学过DP,那么我么第一时间想到的是贪心;

那么,像这样一组数据:13,7,9,16,38,24,37,18,44,19,21,22,63,15

按照贪心的话,求出的应该是13,16,18,19,21,22,63这样一个长度为7的上升子序列

但是,实际上,7 ,9,16,18,19,21,22,63——长度为8,才是正解。

既然有反例了,那么我们就否认贪心。

那怎么办?暴力?枚举?

可以!

但是如果数据太大,那就会TLE了。。。QWQ!

实在不行,我们就请出我们的DP大法!


首先我们日常定义dp[i],表示以第i个数据为结尾的最长上升子序列的长度

我们假设以第j号数据为尾的最长上升子序列的长度为a,如果现在的这个数据i要大于j的话,那么i的最长上升子序列就不需要从最前面算了,就直接是j的最长上升子序列长度+1

#include<bits/stdc++.h>

using namespace std;

int n;//数据的长度
int num[10010];//用于存储数据
int dp[10010];

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>num[i];
    }
    dp[0]=1;//第0号元素默认为1
    int ans=-1;
    for(int i=1;i<=n;i++)
    {
        dp[i]=1;//每一个数的初始子序列的长度必定为1,因为有他自己存在
        for(int j=1;j<i;j++)//j从1开始循环至i-1
        {
            if(num[i]>num[j])//如果符合上升的条件
            {
          dp[i]=max(dp[i],dp[j]+1)//那么i的上升子序列长度就是j的上升子序列的长度+1
            }
        }
        ans=max(ans,dp[i]);//维护答案最大
    }
    cout<<"max="<<ans<<endl;
    return 0;
}

 

posted @ 2019-07-24 10:39  kingderman  阅读(1632)  评论(0编辑  收藏  举报