Longest Increasing Subsequence 浙大OJ2136
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2136
求最长上升子序列个数 严格上升
典型的DP 动态规划。
A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ..., aN) be any sequence (ai1, ai2, ..., aiK), where 1 <= i1 < i2 < ... < iK <= N. For example, the sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e.g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences of this sequence are of length 4, e.g., (1, 3, 5, 8).
Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
Input
The first line of input contains the length of sequence N (1 <= N <= 1000). The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces.
Output
Output must contain a single integer - the length of the longest ordered subsequence of the given sequence.
This problem contains multiple test cases!
The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.
The output format consists of N output blocks. There is a blank line between output blocks.
Sample Input
1
7
1 7 3 5 9 4 8
Sample Output
4
解题思路:如何把这个问题分解成子问题呢?经过分析,发现 “求以ak(k=1, 2, 3…N)为终点的最长上升子序列的长度”是个好的子问题――这里把一个上升子序列中最右边的那个数,称为该子序列的“终点”。虽然这个子问题和原问题形式上并不完全一样,但是只要这N 个子问题都解决了,那么这N 个子问题的解中,最大的那个就是整个问题的解。由上所述的子问题只和一个变量相关,就是数字的位置。因此序列中数的位置k 就是“状态”,而状态 k 对应的“值”,就是以ak 做为“终点”的最长上升子序列的长度。这个问题的状态一共有N 个。状态定义出来后,转移方程就不难想了。假定MaxLen (k)表示以ak 做为“终点”的最长上升子序列的长度,那么:
MaxLen (1) = 1
MaxLen (k) = Max { MaxLen (i):1<i < k 且 ai < ak 且 k≠1 } + 1
这个状态转移方程的意思就是,MaxLen(k)的值,就是在ak 左边,“终点”数值小于ak,且长度最大的那个上升子序列的长度再加1。因为ak 左边任何“终点”小于ak 的子序列,加上ak 后就能形成一个更长的上升子序列。实际实现的时候,可以不必编写递归函数,因为从 MaxLen(1)就能推算出MaxLen(2),有了MaxLen(1)和MaxLen(2)就能推算出MaxLen(3)……
#include <iostream> #include <vector> using namespace std; struct Info{ int index; //序号 1 2 3... int value; //数值 int length; //以该值为终点的最长子序列长度 }; //Info结构体 保存一个终点信息 Info info; vector<Info> V; //保存所有终点数据信息 int main(void) { int c;//测试用例个数 int t;//每个测试用例的数据长度 int e;//每个int元素 cin>>c; for(int i=0;i<c;i++) { cin>>t; V.clear(); int n=0; for(int j=0;j<t;j++) { cin>>e; n++; V.push_back(info); V[n-1].index=n; V[n-1].value=e; if(1==n) { V[n-1].length=1; continue; } int m=0; for(int k=0;k<n;k++) { if(V[k].value<e) { if(V[k].index>m) m=V[k].length; } } V[n-1].length=m+1; } int Lmax=0; for(int p=0;p<t;p++) { if(V[p].length>Lmax) { Lmax=V[p].length; } } cout<<"zuichangshangshengzixuliechangdu: "<<Lmax<<endl; } return 0; }