1.1 基本概念
动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。
1.2、基本思想与策略
基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。
由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。
与分治法最大的差别是:适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)。
1.3、适用的情况
能采用动态规划求解的问题的一般要具有3个性质:
最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。也就是说是求最优解的问题。
无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
有重叠子问题:即子问题之间不是独立的,子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)。
简单说,就是适用于求解极值,最大子序列,最佳时机,最佳路径等最优解的问题。
1.5、求解的基本步骤
动态规划所处理的问题是一个多阶段决策问题。动态规划的设计都有着一定的模式:初始状态→│决策1│→│决策2│→…→│决策n│→结束状态。
一般要经历以下几个步骤,以 股票买卖最佳时机 为例说明:
(1)划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解。如问题,假定第i天卖出股票的最大利润是f(i),每一天都作为一个阶段,那么最后一天的最大利润就是整支股票的最大利润。一般都是以结束点作为基点来划分阶段,如当前的问题,以第i天卖出为基点来划分阶段,如数组最大连续子序和问题,那么就以数组第i个元素作为最大连续子序的结尾来划分阶段。
(2)确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。整个过程中需要记录每个阶段(当天为止)的最低价格和最大利润,只需定义两个变量存储即可,如果需要存储每个阶段的状态,那么可以用数组或者map来存储。
(3)确定决策并写出状态转移方程:根据相邻两个阶段的状态之间的关系来确定决策方法和状态转移方程。通过当天的价格p[i]和当前的最低价格minPrice比较更新最低价格,通过当天卖出获得的最大利润f(i)和当前最大利润maxProfiit比较,更新最大利润。
案例分析:买卖股票的最佳时机
给定一个数组 prices,如[7,1,5,3,6,4],它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回0。
实现代码:
def maxProfit(self, prices: list) -> int:
profit = 0
minval = prices[0]
for i in prices:
minval = min(i, minval)
profit = max(profit, i - minval)
return profit |