五大经典算法之动态规划

一、概念起源

??动态规划,又名DP算法(取自其Dynamic Programming的缩写),最初是运筹学的一个分支,是用来求解决策过程最优化的数学方法。

二、基本思想

??把 多阶段过程 转化为一系列单阶段过程,利用各阶段之间的关系,逐个求解。那什么叫多阶段过程呢?

多阶段过程:首先大家可以思考一下以下这个问题:

假如我们有面值为1元/3元/5元的硬币若干枚,如何用最少的硬币凑够137元?

当然我们可以使用暴力枚举解决这个问题,不够那样复杂度就太高了。我们可以这样考虑,凑齐137元可以看成一个最终目标,我们可以把它细分为先以最少的硬币数量凑齐136元(这样再加1元就137元了)或是133元或是132元 + 1次。然后我们的问题转变为了先以最少的硬币数量凑齐136元或是133元或是132元。看似问题数量变更多了,但是实际问题难度却变小了。

而且这种细分方式可以不断细分,一直细分到接近于0元。而在这个思维过程中,我们就是将解决137元的问题分阶段的完成,而这个过程就叫做 多阶段过程

三、解题步骤(思路)

  1. 利用动态规划思想从上往下思考问题:将多阶段问题转变成更小的多阶段问题(状态转移方程)
  2. 分解至最小的单阶段问题(可直接解决问题)。
  3. 利用循环从下往上解决问题。

四、算法框架

相对于其他基本算法,动态规划算法比较灵活,其主体框架取决于其具体问题,具体问题决定具体的状态转移方程;因此,其不像回溯法有一套“亘古不变”的算法框架;所以以下的算法只能说是解决类似上述硬币问题的DP算法框架,只能算是给各位抛砖引玉。

?变量解释:

??res:存储各阶段问题的答案

??n:最终问题的标记位

??i:循环的索引

??f:某阶段问题的答案与前些阶段问题答案之间的函数关系

void dp(int n) {
  // 定义问题的解数组
  int res[n + 1];
  // 初始化最小的单阶段问题的解
  res[1] = 1 ...
  // 从初始化后的解数组的第一个位置开始循环计算res[i]
  int i = inital;
  while (i <= n) {
    // f函数取决于状态转移方程
    res[i] = f(res[i - 1], res[i - 2], res[i - 3]...);
    i++;
  }
  return res[n];
}  

五、经典实现

经典问题:Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Note that you cannot sell a stock before you buy one.

Example 1:

Input: [7,1,5,3,6,4]

Output: 5

Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.

Not 7-1 = 6, as selling price needs to be larger than buying price.

Example 2:

Input: [7,6,4,3,1]

Output: 0

Explanation: In this case, no transaction is done, i.e. max profit = 0.

int maxProfit(int* prices, int pricesSize) {
  if (pricesSize == 0) {
    return 0;
  }
  int res[pricesSize];
  int min[pricesSize];
  res[0] = 0;
  min[0] = prices[0];
  int i = 1;
  while (i < pricesSize) {
    if (res[i - 1] < prices[i] - min[i - 1]) {
      res[i] = prices[i] - min[i - 1];
    } else {
      res[i] = res[i - 1];
    }
    if (prices[i] < min[i - 1]) {
      min[i] = prices[i];
    } else {
      min[i] = min[i - 1];
    }
    i++;
  }
  return res[pricesSize - 1];
}

原文地址:https://www.cnblogs.com/codernie/p/9085180.html

时间: 2024-11-09 01:02:03

五大经典算法之动态规划的相关文章

经典算法宝典——动态规划思想(六)(2)

1.01背包问题 有N件物品和一个容量为V的背包,第i件物品的体积是c[i],价值是w[i].求解将哪些物品装入背包可使价值总和最大. 解析: 这是最基础的背包问题,特点是每种物品仅有一件,可以选择放或不放.用子问题定义状态,即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值.其状态转移方程便是f[i][v] = max{f[i-1][v], f[i-1][v-c[i]]+w[i]},这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的,所以有必要将它详细解

经典算法之动态规划--求最大公共子序列

作为新人,之前对C,C++了解的比较少,关于算法方面更是一窍不通,但最近却痴迷上了算法,哪怕是前辈们不屑一顾的东东,我弄明白了后都会欣喜若狂! 今天将遇到的问题和java实现贴出来和同为新人的博友分享,老鸟可以可以直接关网页了. 定义: 子序列:一个给定序列的子序列是再该序列中删去若干元素后得到的序列.即:给定{x1,x2,...,xm}和Z={z1,z2,...,zk},X的子序列是指存在一个严格递增下表序列{i1,i2,...ik} 使得对所有的j=1,2,...k,都有zj=xij.例如:

经典算法之动态规划

动态规划让我纠结了好一阵子,背包问题让我觉得不知道怎么入手,到处搜索都是一条条的公式,晦涩难懂.偶然间发现了一个博客写的动态规划解释非常的好,虽然还没完全随心所用,但是总算是入门了,下列内容为转载,附上原地址:http://www.cnblogs.com/sdjl/articles/1274312.html 对于动态规划,每个刚接触的人都需要一段时间来理解,特别是第一次接触的时候总是想不通为什么这种方法可行,这篇文章就是为了帮助大家理解动态规划,并通过讲解基本的01背包问题来引导读者如何去思考动

C语言五大经典算法

分治法 在计算机科学中,分治法是一种很重要的算法.字面上的解释是"分而治 之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再 把子问题分成更小的子问题??直到最后子问题可以简单的直接求解,原 问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序 算法 ( 快速排序 ,归并排序 ) ,傅立叶变换 ( 快速傅立叶变换 )?? 分治法简介 任何一个可以用计算机求解的问题所需的计算时间都与其规模有关. 问题的规模越小,越容易直接求解,解题所需的计算时间也越少.例如,

五大经典算法之回溯法

一.基本概念 ??回溯法,又称为试探法,按选优条件向前不断搜索,以达到目标.但是当探索到某一步时,如果发现原先选择并不优或达不到目标,就会退回一步重新选择,这种达不到目的就退回再走的算法称为回溯法. 与穷举法的区别和联系: 相同点:它们都是基于试探的. 区别:穷举法要将一个解的各个部分全部生成后,才检查是否满足条件,若不满足,则直接放弃该完整解,然后再尝试另一个可能的完整解,它并没有沿着一个可能的完整解的各个部分逐步回退生成解的过程.而对于回溯法,一个解的各个部分是逐步生成的,当发现当前生成的某

[转]五大常用算法:分治、动态规划、贪心、回溯和分支界定

Referred from http://blog.csdn.net/yapian8/article/details/28240973 分治算法 一.基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)…… 任何一个可以用计算机求

五大常用算法:分治、动态规划、贪心、回溯和分支界定

苹果的WWDC ,除了发布了os x 10.10 和IOS8 外,还推出了Swift.详细点击这里 代码总体风格有点像Java,也有点像javascript. 下面给出一些代码段(来自苹果官方手册): println("Hello, world") "var myVariable = 42 myVariable = 50 let myConstant = 42" 摘录来自: Apple Inc. "The Swift Programming Languag

五大常用算法----贪心、动态规划、分支限界、分治算法和回溯算法

五大常用算法之一:贪心算法 所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解. 贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择.必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关. 所以对所采用的贪心策略一定要仔细分析其是否满足无后效性. 五大常用算法之二:动态规划算法 五大常用算法之三:分支限界算法

算法系列15天速成——第四天 五大经典查找【上】

原文:算法系列15天速成--第四天 五大经典查找[上] 在我们的生活中,无处不存在着查找,比如找一下班里哪个mm最pl,猜一猜mm的芳龄....... 对的这些都是查找. 在我们的算法中,有一种叫做线性查找. 分为:顺序查找. 折半查找. 查找有两种形态: 分为:破坏性查找,   比如有一群mm,我猜她们的年龄,第一位猜到了是23+,此时这位mm已经从我脑海里面的mmlist中remove掉了. 哥不找23+的,所以此种查找破坏了原来的结构. 非破坏性查找, 这种就反之了,不破坏结构. 顺序查找