動態規划基礎之最長上升子序列(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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM