题目链接: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. 【UOJ Round #3】

    枚举/二分 C题太神窝看不懂…… 核聚变反应强度 QwQ很容易发现次小的公约数一定是gcd的一个约数,然后……我就傻逼地去每次算出a[1],a[i]的gcd,然后枚举约数……这复杂度……哦呵呵... ...

  2. NoSQL数据存储

    些数据库并不是关系型的,不支持 SQL.它们用来处理庞大的数据集.支持更加灵活的 数据定义以及定制的数据操作.这些被统称为 NoSQL(not only SQL) . dbm family dbm格式 ...

  3. SharePoint2010 对象模型 关联列表

    有关列表的创建其实网上已经有很多文章了,其中练习 :利用Visual Studio 2010创建列表这篇文章个人感觉还不错,这里我强调的是对象模型来创建.在这之前我插入一点其他的东东,导入电子表格和数 ...

  4. 构建配置 Enable multidex

    官方文档 配置方法数超过 64K 的应用 随着 Android 平台的持续成长,Android 应用的大小也在增加.当您的应用及其引用的库达到特定大小时,您会遇到构建错误,指明您的应用已达到 Andr ...

  5. CentOS下ssh sftp配置及权限设置

    运营有异地传输文件的需求,但如果通过QQ等即时通讯软件,不利于文件的集中管理,不方便.而我们办公室的内网机器无法提供外网访问方法,且传输的内容不合适放到公共的网盘或者是云存储上,所以只能用线上负载较低 ...

  6. java web文件下载功能实现 (转)

    http://blog.csdn.net/longshengguoji/article/details/39433307 需求:实现一个具有文件下载功能的网页,主要下载压缩包和图片 两种实现方法: 一 ...

  7. php命名空间的使用,同一个命名空间可以在多个文件中定义

    php namespace的使用,直接打印出已经定义的命名空间 直接上代码,a.php , b.php, c.php , main.php a.php <?php namespace A{ cl ...

  8. Robotframework(2):创建RF第一条可执行的用例

    转载:http://www.cnblogs.com/CCGGAAG/p/7800323.html 上篇,我们说了如何配置基础的环境,配置好了python2.wxPython .robot framew ...

  9. WDCP安装可选组件的快捷命令

    memcache的安装 wget -c http://down.wdlinux.cn/in/memcached_ins.sh chmod 755 memcached_ins.sh ./memcache ...

  10. Mat类具体解释(二)

    Mat::~Mat Mat的析构函数. C++: Mat::~Mat() 析构函数调用Mat::release(). Mat::operator = 提供矩阵赋值操作. C++: Mat& M ...