题目链接:http://codevs.cn/problem/1576/
题目描述 Description

给一个数组a1, a2 ... an,找到最长的上升降子序列ab1<ab2< .. <abk,其中b1<b2<..bk。

输出长度即可。

输入描述 Input Description

第一行,一个整数N。

第二行 ,N个整数(N < = 5000)

输出描述 Output Description

输出K的极大值,即最长不下降子序列的长度

样例输入 Sample Input

5

9 3 6 2 7

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

【样例解释】

最长不下降子序列为3,6,7

解题思路

参考:北大郭炜老师

1.找子问题:“求以ak( k=1, 2, 3…N)为终点的最长上升子序列的长度”
一个上升子序列中最右边的那个数,称为该子序列的“终点”。
虽然这个子问题和原问题形式上并不完全一样,但是只要这N个子问题都解决了,那么这N个子问题的解中,最大的那个就是整个问题的解。

2. 确定状态
子问题只和一个变量-- 数字的位置相关。因此序列中数的位置k 就是“状态”,而状态 k 对应的“值”,就是以a[k]做为“终点”的最长上升子序列的长度。状态一共有N个。

3. 找出状态转移方程

maxLen [k]表示以a[k]做为“终点”的最长上升子序列的长度那么:
初始状态: maxLen [1] = 1
maxLen[k]= max { maxLen [i]: 1<=i < k 且 a[i ]< a[k]且 k≠1 } + 1
若找不到这样的i,则maxLen[k] = 1

maxLen[k]的值,就是在a[k]左边,“终点”数值小于a[k] ,且长度最大的那个上升子序列的长度再加1。因为a[k]左边任何“终点”小于a[k]的子序列,加上a[k]后就能形成一个更长的上升子序列 。

 1 #include <stdio.h>
2 #define maxN 5005
3 int n,a[maxN],maxLen[maxN];//maxLen[k]表示以a[k]做为“终点”的最长上升子序列的长度
4 int main(int argc, char *argv[])
5 {
6 int i,j;
7 scanf("%d",&n);
8 for(i=0;i<n;i++) { scanf("%d",&a[i]); maxLen[i]=1; }
9
10 for(i=1;i<n;i++)//枚举所有子序列的终点
11 {
12 for(j=0;j<i;j++)//枚举以a[i]做终点的子序列中a[i]的前缀元素
13 {
14 if(a[j]<a[i])//尝试用a[j]做a[i]的直接前缀形成新的子序列
15 {
16 maxLen[i]=(maxLen[j]+1>maxLen[i]?maxLen[j]+1:maxLen[i]);
17 }
18 }
19 }
20 printf("%d\n",maxLen[n-1]);
21 return 0;
22 }

上面的代码写错了,抱歉。更正如下:

 #include <stdio.h>
#define maxN 5005
int main(int argc, char *argv[])
{
int i,j,t;
int n,a[maxN],maxLen[maxN];//maxLen[k]表示以a[k]做为“终点”的最长上升子序列的长度
int max; scanf("%d",&n);
for(i=;i<n;i++) { scanf("%d",&a[i]); maxLen[i]=; }
for(i=;i<n;i++)//枚举所有子序列的终点
{
for(j=;j<i;j++)//枚举以a[i]做终点的子序列中a[i]的前缀元素
{
if(a[j]<a[i])//尝试用a[j]做a[i]的直接前缀形成新的子序列
{
maxLen[i]=(maxLen[j]+>maxLen[i]?maxLen[j]+:maxLen[i]);
}
}
}
max=maxLen[];
for(i=;i<n;i++)
if(maxLen[i]>max) max=maxLen[i];
printf("%d\n",max);
return ;
}

思考题 : 如何改进程序,使之能够输出最长上升子序列 ?

思路:新增pre[ ],其中pre[k]=x表示在a[ ]序列构成的若干个上升子序列中,a[k]的前驱是a[x]。一开始pre[ ]全部初始化为-1表示一开始所有元素的前驱都是自己本身。在循环求解maxLen[i]的同时,更新pre[i]。最后在扫描出maxLen[ ]最大值为maxLen[i]以后,从pre[i]往前推即可。假如要顺序输出该最长上升子序列,可以把逆推pre[ ]的过程保存再输出。

参考代码:

 #include<stdio.h>
#include<string.h>
#define maxN 5005
int main(int argc, char *argv[])
{
int i,j,t;
int n,a[maxN],maxLen[maxN];//maxLen[k]表示以a[k]做为“终点”的最长上升子序列的长度
int max;
int pre[maxN];
int c[maxN],maxIndex; memset(pre,-,sizeof(pre)); scanf("%d",&n);
for(i=;i<n;i++) { scanf("%d",&a[i]); maxLen[i]=; } for(i=;i<n;i++)//枚举所有子序列的终点
{
for(j=;j<i;j++)//枚举以a[i]做终点的子序列中a[i]的前缀元素
{
if(a[j]<a[i])//尝试用a[j]做a[i]的直接前缀形成新的子序列
{
if(maxLen[j]+>maxLen[i])
{
maxLen[i]=maxLen[j]+;
pre[i]=j;
}
}
}
}
max=maxLen[];
for(i=;i<n;i++)
if(maxLen[i]>max) { max=maxLen[i]; maxIndex=i; }
printf("%d\n",max); j=;
c[j++]=a[maxIndex];
while(pre[maxIndex]!=-)
{
maxIndex=pre[maxIndex];
c[j++]=a[maxIndex];
}
for(i=j-;i>=;i--)
{
printf("%d ",c[i]);
}
printf("\n");
return ;
}

输出最长上升子序列的另一种思路:

 #include <stdio.h>
int n,size,a[][],s,ans,next;
int main(int argc, char *argv[])
{
scanf("%d",&n);
for(int i=;i<n;i++)
{
int t;
scanf("%d",&t);
a[i][]=t;a[i][]=;a[i][]=;
//a[i][1]表示以a[i][0]开头的最长上升子序列的长度。
//a[i][2]表示在以a[i][0]开头的最长上升子序列中a[i][0]的下一个数在原序列中的下标。
} for(int i=n-;i>=;i--)
{
size=next=;
for(int j=i+;j<n;j++)
if(a[j][]>a[i][]&&a[j][]>size) {size=a[j][];next=j;}
if(size>) {a[i][]=size+;a[i][]=next;}
} ans=;
for(int i=;i<n;i++)
if(a[i][]>a[ans][]) ans=i; printf("%d\n",a[ans][]); /*for(int i=0;i<n;i++)
printf("%d %d %d %d\n",a[i][0],a[i][1],a[i][2],i);*/ int i=ans;
while(a[i][]>)
{
printf("%d ",a[i][]);
i=a[i][];
}
printf("%d\n",a[i][]);
return ;
}

测试OJ地址:

http://noi.openjudge.cn/ch0206/1759/

http://bailian.openjudge.cn/practice/2757/

codevs 1576 最长严格上升子序列的更多相关文章

  1. codevs 1576最长严格上升子序列

    传送门 1576 最长严格上升子序列  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 黄金 Gold   题目描述 Description 给一个数组a1, a2 ... an ...

  2. codevs——1576 最长严格上升子序列(序列DP)

     时间限制: 1 s  空间限制: 256000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 给一个数组a1, a2 ... an,找到最长的上升降子序列 ...

  3. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  4. codevs 2185 最长公共上升子序列

    题目链接: codevs 2185 最长公共上升子序列codevs 1408 最长公共子序列 题目描述 Description熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目.小沐沐先让奶牛研究了最长上升 ...

  5. codevs——T1576 最长严格上升子序列

    http://codevs.cn/problem/1576/  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Descr ...

  6. wikioi 1576 最长严格上升子序列

    简单的最长严格上升子序列的题 dp[i]表示到a[i]这个数为最后的时候最大的长度是多少 然后就差不多了吧~ #include <cstdio> #include <cmath> ...

  7. codevs 2185 最长公共上升子序列--nm的一维求法

    2185 最长公共上升子序列  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 钻石 Diamond 题目描述 Description 熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目 ...

  8. [CODEVS] 3955 最长严格上升子序列(加强版)

    题目描述 Description 给一个数组a1, a2 ... an,找到最长的上升降子序列ab1<ab2< .. <abk,其中b1<b2<..bk. 输出长度即可. ...

  9. dp练习(5)——最长严格上升子序列

    1576 最长严格上升子序列  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 给一个数组a1, a2 ... ...

随机推荐

  1. [转]php的public、protected、private三种访问控制模式的区别

    FROM : http://blog.163.com/weiwenjuan_bj/blog/static/14035033620129304183850/?suggestedreading publi ...

  2. FinalizableReference, FinalizablePhantomReference, FinalizableReferenceQueue

    FinalizableReference /* * Copyright (C) 2007 The Guava Authors * * Licensed under the Apache License ...

  3. [leetcode]Median of Two Sorted Arrays @ Python

    原题地址:https://oj.leetcode.com/problems/median-of-two-sorted-arrays/ 题意:There are two sorted arrays A ...

  4. 如何查看Isilon的节点的CPU的信息?

    使用Isilon自带的命令 isi_hw_status 使用如下的命令 dmidecode --type processor 笔者只是想了解一下F800的CPU有多少个core.上面的命令都可以获得这 ...

  5. 不用IDE写C#的Hello World

    用Visual Studio等IDE写C#的Hello World非常简单,但脱离了IDE你能不能打印出Hello World呢?这不是说工作时脱离IDE,而是学习一下CLR的执行模型. Hello ...

  6. php7安装mongoDB扩展

    本文我们使用pecl命令来安装 首先来到php7的安装目录 $ /usr/local/php7/bin/pecl install mongodb 回车,执行成功后,会输出以下结果: …… Build ...

  7. 转:EM算法总结

    https://applenob.github.io/em.html EM算法总结 在概率模型中,最常用的模型参数估计方法应该就是最大似然法. EM算法本质上也是最大似然,它是针对模型中存在隐变量的情 ...

  8. [转]PostgreSQL Replication之扩展与BDR

    原文:https://www.cnblogs.com/xmzzp/p/6284300.html postgres 实现master, slave ,且master是多主. -------------- ...

  9. OpenNebula学习第一节OpenNebula Front-end Installation

    一.说说情怀 随着公司硬件开发资源的不足,构建一个云平台似乎重要了起来.当然,也不是这个平台搭建的主力,出于工作的需求和个人兴趣爱好,接下来就来学习一下OpenNebula相关的东西,这是第一节课,先 ...

  10. js递归遍历key

    需求:根据Json对象,查找到某key所有值 var obj = { first: "1", second: { name: "abc", mykey: &qu ...