總時間限制: 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
解題思路:
1.找子問題
“求序列的前n個元素的最長上升子序列的長度”是個子問題,但是這樣分解子問題
不具有“無後效性”
假設F(n) = x,但可能有多個序列滿足F(n) = x,有的序列的最後一個元素比an+1小
,則加上an+1就能想成更長上升子序列;有的序列最後一個元素不必an+1小...故以後
的情形將受到狀態n的影響,不符合“無後效性”
2.確定狀態
子問題之和一個變量--數字的位置有關。因此序列中數字的位置k就是狀態,而狀態
k對應的值就是以ak作爲終點的最長上升子序列的長度。
狀態一共有N個。
3.確定一些初始狀態
在本狀態的初始狀態中是將狀態數組len[i]初始化爲1.
4.找出狀態轉移方程
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 <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int a[maxn],len[maxn];
int n;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
len[i] = 1;
}
//“人人爲我”遞推版動歸程序
/*for(int i=0;i<n;i++){
for(int j=0;j<i;j++){
if(a[j]<a[i])
len[i] = max(len[i],len[j]+1);
}
}*/
//"我爲人人"版
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(a[j]>a[i])
len[j] = max(len[j],len[i]+1);
}
}
int Max = -1;
for(int i=0;i<n;i++)
Max = max(Max,len[i]);
printf("%d\n",Max);
printf("%d\n",*max_element(len,len+n));
return 0;
}