首页 > 代码库 > SCAU-OJ 8596 最长上升子序列
SCAU-OJ 8596 最长上升子序列
时间限制:300MS 内存限制:1000K
提交次数:255 通过次数:118
题型: 编程题 语言: 无限制
Description
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, 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 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.
输入格式
There are several test cases. Every test case includes two lines.
The first line contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each,
separated by spaces. 1 <= N <= 1000
When N is 0, it indicates test to end.
输出格式
Output must contain a single integer for every test case ---- the length of the longest ordered subsequence of the given sequence.
输入样例
7
1 7 3 5 9 4 8
6
1 8 3 6 5 9
5
1 2 3 4 5
0
输出样例
4
4
5
提示
一,对输入字符串的处理
注意:这道题和其他题的输入输出不同,这题是接收多组数据而非单组,以0来判别结束.
大家在接受数据的时候,不要用(c=getchar())!=‘\n‘诸如此类一个字符一个字符接受,然后判断是否是回车符号来结束一行的输入,
这样的方式在你本机运行不会有问题,但OJ系统中会有错误,无法输出结果,因为测试平台行末并非‘\n‘字符。
这里接受数据用scanf的%s,或cin等,会自动判别结束字符的,你就不要在你程序里专门去判别或吸收回车字符。
对于最后一组数据输入为0表示结束,只要判断接受的第一个字符是否为0且字符串长度为1就结束,无须去处理回车字符。
二,算法的动态规划思想
考虑采用动态规划算法,针对每个元素,以该元素结尾的最长有序子序列作为子问题,
计算出每个子问题的最大长度用“表”记录下来。先写出递推关系式再编程实现。
设f(i)表示:从左向右扫描过来直到以a[i]元素结尾的序列,可获得的最长上升子序列的长度,且最长上升子序列包含a[i]元素(1<=i<=n)。
(这里大家思考一下,为何要这样假设子问题和子问题最优解f(i)?有同学问:为何最长上升子序列要包含a[i]元素(1<=i<=n)?
因为你所设的子问题要和更下一级子问题关联起来。
如果长度为i序列的最长上升子序列中没有规定包含a[i]元素,那如何和其前缀的最长上升子序列问题关联起来呢,那样显然是比较麻烦的。)
f(i)是从f(1),f(2),……到f(i-1)中找最大的一个值,再加1,或者就是1。
这主要得看a[i]这个元素能否加入到之前已经获得的最长上升子序列当中去,
如果能加入,是之前已获得的最长上升子序列长度加1;
如果不能加入,就开始一个新的上升子序列,长度为1。
最后,所要求的整个序列的最长上升子序列长度为 max{ f(i): 1<=i<=n }
f(i)的递推公式如下:
(1)f(i) = 1 当i=1;
(2)f(i) = max{f(j)+1} 当a[i]>a[j],j大于等于1且小于i,i>1;
(3)f(i) = 1 当对任意j,(j大于等于1且小于i),都有a[i]<=a[j];
例子,对于序列:4 2 6 3 1 5 2
i = 1 2 3 4 5 6 7
a[i] = 4 2 6 3 1 5 2
f(i) = 1 1 2 2 1 3 2
这里max{f(i)}=3为原问题所求的最长上升子序列的长度。
效率分析:
f(i)的计算不超过O(n),因此,整个算法为O(n^2)。
来自 <http://www.scaucs.net:8000/uoj/common_problem_view_PUBLIC.html?problemId=8596&from=list>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <stdio.h> #include <math.h> #include <stdlib.h> #include <string.h> int s[1005],d[1005]; int main() { int n,i,j,m,mm; while ( scanf ( "%d" ,&n)&& n != 0) { memset (d,0, sizeof (d)); mm = 0; for (i = 1; i <= n; i++) scanf ( "%d" ,&s[i]); for (i = 1; i <= n; i++) { m = 0; for (j = 1; j < i; j++) { if (s[i] >= s[j] && d[j] > m) m = d[j]; } d[i] = 1 > m + 1 ? 1 : m + 1; if (d[i] > mm) mm = d[i]; } printf ( "%d\n" ,mm); } return 0; } |