同類的問題還有「最長上公升子串行」, 「最長下降子串行」, …
他們的不同就在於定義的core規則不同, 有的是》=, 有的是》, 有的是<
由此啟發, 我們可以在解決其他的問題,不一定是比較數的大小的問題裡面抽象出這種模型.
下面介紹這種動態規劃入門都會介紹的問題的思路.
首先我們從頭開始分析這個問題.
對這個序列中的每乙個數的」有」和」無」分兩種情況討論. **實現上就是遞迴.
時間複雜度就是o(2^n)
**實現上較為簡單. 不展示
動態規劃的問題是無後效性的, 每個問題都可以分解為更小的子問題, 從而求解.
這道題也不例外.
這個序列的每乙個數為止都有乙個解, 作為子問題的解. 後面的問題的解就是從這些子問題的最優解繼承過來的.
so, 給這個序列的解建立陣列dp[n], 0 - n分別是截止到ai的解.
當下乙個數要加入來的時候, 有兩種情況這種方法的時間複雜度是o(n^2), 可以看到相比於前面暴力遞迴的方法有了極大的進步.前面的數都比當前數更大, 因此以這個數為止的最長不下降子串行的長度就是1. 遍歷到第乙個數的情況也包含在內.
前面的數有不比當前數大的, 那麼這個數的結果dp[i] = max(dp[i], dp[j] + 1). 這個過程遍歷前面所有數的dp[j]進行比較.
最後的答案就是所有dp[i]裡面的最大值.
**通過樣例, 但不一定能過題, 請謹慎使用.
#include
#include
using
namespace
std;
int main()
int dp[(int)v.size()] = , ans = 1;
for (int i = 1; i < (int)v.size(); ++i)
ans = max(ans, dp[i]);
}cout
<< ans;}/*
81 2 3 -9 3 9 0 11
*/
這個方法也是dp方法
時間複雜度可以從o(n^2)降到o(n log n).
我們從最長上公升子串行的角度來**
假設對乙個序列n[1…9] = , 維護乙個單調陣列, 使得這個陣列為最長上公升子串行. 設這個陣列為d[ ].
對n[1] = 2, 使得d[1] = 2;
對n[2] = 1, 因為1比2小, 所以修改d[1]的值, 使其為1
對n[3] = 5, 5比1大, 所以len++, d[2] = 5
對n[4] = 3, 3比1大比5小, 所以替換掉5, 使d[2] = 3
對n[5] = 6, 6比d[2]大, 所以len++, d[3] = 6
對n[6] = 4, 4比3大比6小, 所以替換掉6, 使d[3] = 4
對n[7] = 8, 8比4大, 所以len++, 使d[4] = 8
對n[8] = 9, 9比8大, 所以len++, 使d[5] = 9
對n[9] = 7, 7比4大比8小, 所以替換掉8, 使d[4] = 7.
至此這個序列遍歷完了, 最小的長度也出來了. 最後的序列是1 3 4 7 9, len = 5
仔細琢磨會覺得,如最後一步操作, 為什麼後面的7反而到他前面的8, 9的前面去了.其實仔細一想並無問題, 因為即使7出現在前面, 它並不影響最終結果,因為我們已經得出最後結果就是len, 而以7為結尾的最長序列在該題中是len - 1, 如果後面還有序列,那麼這裡把7替換掉8會使得當前狀態更優, 因為這樣的修改是不會改變當前結果的, 但是確實後續最優狀態的基礎. 而這道題的動態規劃思想就是這樣, 不斷地獲取最優狀態.
經過前面的分析我們也許會發現, 這個dp的過程無法儲存中間結果, 也就是說我們只能知道最長的子串行是多長, 而無法得到是哪個序列.可謂是有利有弊.
利用我們維護的陣列的單調性, 我們可以用二分法查詢這個比當前數更大數的位置, 從而方便的實現替換.
所以時間複雜度為o(n log n).
#include
#include
#include
using
namespace
std;
int main()
for (int i = 0; i < (int)v.size(); ++i)
}for (int i = 0; i < (int)vec.size(); ++i)
cout
<< endl;
cout
<< "len == "
<< vec.size() << endl;}/*
92 1 5 3 6 4 8 9 7
*/
線性DP 最長不下降子串行 LIS
題目 例1 求最長不下降子串行。由n個不相同的整數組成的數列,記為 a 1 a 2 a n 且a i a j i j 例如,3,18,7,14,10,12,23,41,16,24.若存在i1 i2 3 e且有a i1 2 e 則稱其為長度為e的不下降子串行。如上例中3,18,23,24就是乙個長度為...
最長不下降子串行LIS
最長上公升子串行問題是解決很多問題的根本,它能幫助你理解二分的思想。考慮一下 對於乙個序列 n nn 請你查詢n nn中最長的子串行a aa,使得任意 i i j 時 a i a i a i a i a i a i 例如乙個長度為5 55的n nn 5553 331112 22444 顯然,它的最長...
LIS最長不下降子串行
在乙個序列中找到乙個最長的子串行 可以不連續 使得這個子串行不下降,即非遞減的。核心部分找到狀態轉移方程 dp i max j 1,2,i 1 a j 附上我的 include include includeusing namespace std const int maxn 10010 int d...