最长上升子序列

时间限制:300MS  内存限制:1000K

提交次数:255 通过次数:118

题型:编程题   语言: 无限制

Description

A numeric sequence ofai is ordered if a1 < a2 < ... < aN.
Let the subsequence of the given numeric sequence (a1, a2, ..., aN) be anysequence (ai1, ai2, ..., aiK), where 1 <= i1 < i
2 < ... < 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, whengiven the numeric sequence, must find the length of its longest orderedsubsequence.

 

 

输入格式

There are severaltest cases. Every test case includes two lines.
The first line contains the length of sequence N. The second line contains theelements 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 asingle integer for every test case ---- the length of the longest orderedsubsequence 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>


#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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值