最长上升子序列又名最长不下降子序列,英文名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; }