本文为原创,转载请注明:http://www.cnblogs.com/kylewilson/

题目出处:

http://poj.org/problem?id=2533

题目描述:

如果ai1 < ai2 < ... < aik ,1 <= i1 < i2 < ... < iK <= N,则该序列为有序;给一个序列,找出一个最长的上升序列,如 (a1, a2, ..., aN)有一个上升序列为 (ai1, ai2, ..., aiK),1 <= i1 < i2 < ... < iK <= N;

例如 (1, 7, 3, 5, 9, 4, 8) 有上升序列如 (1, 7), (3, 4, 8),最长的上升序列为(1, 3, 5, 8),长度为4

求一个最长上升序列的长度

输入:

第一行一个数N,表示给定序列长度为N,1 <= N <= 1000

第二行N个数,表示序列的每个数值,每个数范围为[0,10000]

7

1 7 3 5 9 4 8

思路分析:

题目是一个求最优解的问题,所以首先想到的就是用动态规划的思想来解决。

动态规划的本质就是先求解小问题的最优解,再通过小问题的最优解推导出大问题的最优解。

下面就通过这个题目,来说明如何找出一个问题背后蕴含的动态规划本质。

我常用的方法,暂且称之为“最终状态反推法”。。。

步骤一:

假设一个最终的状态。

比如该题目,最终的状态一定是在该数组中选出部分的数字,并且选出的数字组成一个上升的序列,因为对于每一个数要么选择,要么不选。

如图P1.1, 红色框里的数字就是一个合理的最终状态。[1, 3, 5, 7]为上升序列,且长度为4是一个最优解。

步骤二:

通过已知的最终状态扩大数据规模。

步骤一就是找小问题的解,我们其实也并没有真正去讲怎么找一个最优解,只是先假设一个最优解就是如上所示。

然后用上面的状态,去扩大数据规模,有点类似数学归纳法的思想。

如图P1.2

如果在原数组的最后一位再增加一个数,比如绿色框里的数字8,这种操作可以抽象为把N个数的数组扩大为N+1。

然后再结合步骤一中是如何假设的最终状态呢?

对于每一个数字要么选,要么不选,就只有两种情况。

情况1

如果增加的数字不选,N+1个数的最优解还是和N个数的最优解是一样的

设F[n]表示N个数能组成上升序列的最长长度,则F[n+1]=F[n]

情况2

如果增加的数字要选,则N+1个数的最优解可以通过N个数推导出来,即F[n+1]=F[n]+1,因为多选了一个数,所以肯定是加1。

步骤三

找出策略及条件。

现在也就是要详细分析一下上面的不同情况,具体是应该如何去选择。

比如一个很具体的问题,既然上面我们说到了,要么选择,要么不选择,那么你就会问,什么时候应该选择,什么时候不选择呢?

再回到题目结合具体的问题背景,我们是要找一个上升序列。对于步骤二中的情况1,如果该数要选择,自然就是增加的数是大于F[n]的解中最后的那一个数,如图P1.2。

对于步骤二中的情况2,如果该数不选择,也自然就是增加的数小于F[n]的解中最后的那一个数,如图P1.3

上面又引入了一个新的问题,必须知道之前的最优解具体选择了哪些数,不过其实我只关心最后的那一个数,那就是最后的那一个数必须要记录下来。

步骤四

找出状态及递推公式。

对于之前的F[n]只记录了长度,这明显是不够的,所以没法递推。

我们重新假设状态,

以f[i][j]表示前i个数中以第j个数结尾的最优长度,则递推公式如下:

f[i][i]=f[i-1][j]+1,其中a[i]>a[j],即第i个数选择

f[i][j]=f[i-1][j],其中 0<j<i,即第i个数不选择

最后遍历f[n][i], 0<i<n,便可得到最优解

但到此还没有结束,因为动态规划中的状态与决策可以有很多的定义,本质也是一个优化剪枝的穷举,所以不同的状态与决策有不同的效率。

再仔细思想,我只需要知道上一次最优解最后选择的那一个数是多少;

则假设f[i]表示以第i个数结尾的最大长度

f[i]=max(f[j]+1),其中a[i]>a[j],

f[i]=1,其中a[i]不大于前面任何一个解的最后一个数,

最后遍历f[i],0<i<=n,便可得到最优解。

C++源码如下:

github: https://github.com/Kyle-Wilson1/Poj/tree/master/P2533

  1. #include <iostream>
  2. #include <fstream>
  3. #include <vector>
  4.  
  5. using namespace std;
  6.  
  7. int maxOfTwo(int a, int b) {
  8. return a > b ? a : b;
  9. }
  10.  
  11. int main() {
  12.  
  13. ifstream fin("a.in");
  14. ofstream fout("a.out");
  15.  
  16. int i, j, n, maxLength = 0;
  17. fin >> n;
  18.  
  19. vector<int> num(n, 0);
  20. vector<int> f(n, 0);
  21.  
  22. for (i = 0; i < n; i++) {
  23. fin >> num[i];
  24. }
  25.  
  26. for (i = 0; i < n; i++) {
  27. f[i] = 1;
  28. for (j = 0; j < i; j++) {
  29. if (num[i] > num[j]) {
  30. f[i] = maxOfTwo(f[i], f[j] + 1);
  31. };
  32. }
  33. maxLength = maxOfTwo(maxLength, f[i]);
  34. }
  35.  
  36. fout << maxLength << endl;
  37. fin.close();
  38. fout.close();
  39.  
  40. return 0;
  41. }

Poj-P2533题解【动态规划】的更多相关文章

  1. poj 3783 Balls 动态规划 100层楼投鸡蛋问题

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4098409.html 题目链接:poj 3783 Balls 动态规划 100层楼投鸡蛋问题 ...

  2. [POJ 2923] Relocation (动态规划 状态压缩)

    题目链接:http://poj.org/problem?id=2923 题目的大概意思是,有两辆车a和b,a车的最大承重为A,b车的最大承重为B.有n个家具需要从一个地方搬运到另一个地方,两辆车同时开 ...

  3. poj 2385【动态规划】

    poj 2385 Apple Catching Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14007   Accepte ...

  4. 洛谷P1002 过河卒 题解 动态规划

    题目链接:https://www.luogu.com.cn/problem/P1002 题目大意 棋盘上\(A\)点有一个过河卒,需要走到目标\(B\)点.卒行走的规则:可以向下.或者向右.同时在棋盘 ...

  5. poj 2229 一道动态规划思维题

    http://poj.org/problem?id=2229 先把题目连接发上.题目的意思就是: 把n拆分为2的幂相加的形式,问有多少种拆分方法. 看了大佬的完全背包代码很久都没懂,就照着网上的写了动 ...

  6. [POJ 2063] Investment (动态规划)

    题目链接:http://poj.org/problem?id=2063 题意:银行每年提供d种债券,每种债券需要付出p[i]块钱,然后一年的收入是v[i],到期后我们把本金+收入取出来作为下一年度本金 ...

  7. POJ 1088 滑雪 -- 动态规划

    题目地址:http://poj.org/problem?id=1088 Description Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当 ...

  8. poj 1159 Palindrome - 动态规划

    A palindrome is a symmetrical string, that is, a string read identically from left to right as well ...

  9. [LeetCode]Longest Palindromic Substring题解(动态规划)

    Longest Palindromic Substring: Given a string s, find the longest palindromic substring in s. You ma ...

  10. poj 3744 题解

    题目 题意: $ yyf $ 一开始在 $ 1 $ 号节点他要通过一条有 $ n $ 个地雷的道路,每次前进他有 $ p $ 的概率前进一步,有 $ 1-p $ 的概率前进两步,问他不领盒饭的概率. ...

随机推荐

  1. Python之复制列表

    将一个列表的数据复制到另外一个列表中. 1 a = [1,2,3] #定义列表a 2 3 b = a[:] #将列表a的切片赋值给b,也可以理解为将b的值设置为a[:] 4 5 print(a) #打 ...

  2. DotNet .Net Framework与Net Core与Net Standard 以及.NET5

    Net Framework 是什么 1.Net Framework 是Net的一种实现,在此类库上我们可以使用C#,VB,F#进行程序编写,主要用于构建Windows 下的应用程序 2.有两部分组成部 ...

  3. 【命令】gunzip命令

    gunzip命令是拿来解以.gz格式的压缩包,其语法和参数选项和gzip一样,我们可以使用gzip来实现,请查看:gzip命令使用方法

  4. 自定义 demo 集合

    各种写着玩的自定义控件demo 有时网上看到一些比较有意思的开源项目,有时间的话就会自己也撸一个出来,但是一般只关注实现样式.动画等,不会太去细致完整地完成,俗称占个坑~ 持续更新中... githu ...

  5. 学习 Gin 问题总结 2020.12.29

    学习 Gin 问题总结 2020.12.29 数据绑定与解析 BindXXX,ShouldBindXXX和ShouldBindWith区别 BindXXX 会自动返回信息,输入无效时,在header写 ...

  6. [leetcode]61. Rotate List反转链表k个节点

    类似于找链表的后k个节点 不同的是要把前边的接到后边 public ListNode rotateRight(ListNode head, int k) { //特殊情况 if (head==null ...

  7. CMS、G1收集器

    目录 CMS.G1收集器 1.CMS收集器 1.1.原理 1.2.不足 2.G1收集器 2.1.特点 2.2.执行过程 CMS.G1收集器 1.CMS收集器 CMS(Concurrent Mark S ...

  8. WebSocket入门及使用指南

    最近在一个项目中,需要使用到websocket,于是就花了一点时间来熟悉websocket并总结写篇blog. 为何使用websocket 在浏览器与服务器通信间,传统的 HTTP 请求在某些场景下并 ...

  9. JavaScript 函数节流和函数去抖

    概念 函数防抖(debounce) 当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间 函数节流(throttle) 预先设定一个执行周期,当调用动作的时刻大于等于执 ...

  10. centos7中redis安装配置

    1.官网下载对应版本,本例以5.0.5为例 2.tar -zxvf xxxxx 并mv到安装目录 3.进入redis-5.0.5目录下,执行编译命令 make 4.编译完成后,经redis安装到指定目 ...