百练2757:最长上升子序列
題目要求
總時間限制: 2000ms 內存限制: 65536kB
描述
一個數的序列bi,當b1 < b2 < … < bS的時候,我們稱這個序列是上升的。
對于給定的一個序列(a1, a2, …, aN),我們可以得到一些上升的子序列(ai1, ai2, …, aiK),這里1 <= i1 < i2 < … < iK <= N。
比如,對于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。
這些子序列中最長的長度是4,比如子序列(1, 3, 5, 8)。
你的任務,就是對于給定的序列,求出最長上升子序列的長度。
輸入
輸入的第一行是序列的長度N (1 <= N <= 1000)。
第二行給出序列中的N個整數,這些整數的取值范圍都在0到10000。
輸出
最長上升子序列的長度。
樣例輸入
7
1 7 3 5 9 4 8
樣例輸出
4
來源
翻譯自 Northeastern Europe 2002, Far-Eastern Subregion 的比賽試題
解題思路
1.找子問題
“求序列的前n個元素的最長上升子序列的長度”是個子問題,但是這樣分解子問題,不具有“無后效性”:假設F(n)=x,但可能有多個序列滿足F(n)=x。有的序列的最后一個元素比an+1小,則加上an+1就能形成更長上升子序列;有的序列最后一個元素不比an+1小……以后的事情受如何達到狀態n的影響,不符合“無后效性”。
“求以ak(k=1, 2, 3…N)為終點的最長上升子序列的長度”一個上升子序列中最右邊的那個數,稱為該子序列的“終點”。雖然這個子問題和原問題形式上并不完全一樣,但是只要這N個子問題都解決了,那么這N個子問題的解中,最大的那個就是整個問題的。
2.確定狀態
子問題只和一個變量-- 數字的位置相關。因此序列中數的位置k 就是“狀態”,而狀態 k 對應的“值”,就是以ak做為“終點”的最長上升子序列的長度狀態一共有N。
3.找出狀態轉移方程
maxLen (k)表示以ak做為“終點”的最長上升子序列的長度那么:
初始狀態:maxLen (1) = 1 。
maxLen (k) = max { maxLen (i):1<=i < k 且 ai < ak且 k≠1 } + 1
若找不到這樣的i,則maxLen(k) = 1。
maxLen(k)的值,就是在ak左邊,“終點”數值小于ak ,且長度最大的那個上升子序列的長度再加1。因為ak左邊任何“終點”小于ak的子序列,加上ak后就能形成一個更長的上升子序。
代碼
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int MAXN =1010; int a[MAXN]; int maxLen[MAXN]; int main() {int N; cin >> N;for( int i = 1;i <= N;++i){cin >> a[i]; maxLen[i] = 1;}for( int i = 2; i <= N; ++i){//每次求以第i個數為終點的最長上升子序列的長度for( int j = 1; j < i; ++j)//察看以第j個數為終點的最長上升子序列if( a[i] > a[j] )maxLen[i] = max(maxLen[i],maxLen[j]+1);}cout << * max_element(maxLen+1,maxLen + N + 1 );return 0; } //時間復雜度O(N^2)總結
以上是生活随笔為你收集整理的百练2757:最长上升子序列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: The Triangle
- 下一篇: Common Subsequence