1 一个问题:换零钱方式的统计

SICP 第一章 1.2.2 树形递归中,有这么一问题:给了半美元,四分之中的一个美元。10美分,5美分和1美分的硬币。将1美元换成零钱,一共同拥有多少种不同方式?更一般的问题是,给定了随意数量的现金,我们能写一个程序,计算出全部换零钱方式的种数吗?

2 动态规划的基本模型

动态规划(Dynamic programming,DP),是研究一类最优化问题的方法,通过把原问题分解为相对简单的子问题的方式求解复杂问题。动态规划处理的也就是是多阶段决策最优化问题,这一类问题可将过程分成若干个互相联系的阶段,在每一阶段都作出决策,从而使整个过程达到最好的结果。

因此各个阶段决策的选取不能随意确定,它依赖于当前面临的状态。又影响以后的发展。当各个阶段决策确定后,就组成一个决策序列,从而也就确定了整个过程的一条活动路线。这样的把一个问题看做是一个前后关联具有链状结构的多阶段过程称为多阶段决策过程。

动态规划著名的应用实例有:求解最短路径问题,背包问题,项目管理,网络流优化等。动态规划的基本模型例如以下:

  1. 确定问题的决策对象
  2. 对决策过程划分阶段
  3. 对各阶段确定状态变量
  4. 依据状态变量确定费用函数和目标函数
  5. 建立各阶段状态变量的转移过程。确定状态转移方程

3 使用动态规划的一般前提

3.1 满足动态规划的最优化原理

作为整个过程的最优策略具有例如以下性质:不管过去的状态和决策怎样,对前面的决策所形成的当前状态而言,余下的诸决策必须构成最优策略。

通俗理解就是子问题的局部最优将导致整个问题的全局最优,即问题具有最优子结构的性质,也就是说一个问题的最优解仅仅取决于其子问题的最优解,非最优解对问题的求解没有影响。

3.2 满足动态规划的无后效性原则

所谓无后效性原则。指的是这样一种性质:某阶段的状态一旦确定,则此后过程的演变不再受此前各状态及决策的影响。也就是说,“未来与过去无关”,当前的状态是此前历史的一个完整总结,此前的历史仅仅能通过当前的状态去影响过程未来的演变。

详细地说,假设一个问题被划分各个阶段之后,阶段 I 中的状态仅仅能由阶段 I+1 中的状态通过状态转移方程得来,与其它状态没有关系,特别是与未发生的状态没有关系,这就是无后效性。从图论的角度去考虑。假设把这个问题中的状态定义成图中的顶点,两个状态之间的转移定义为边,转移过程中的权值增量定义为边的权值,则构成一个有向无环加权图,因此,这个图能够进行“拓扑排序”,至少能够按他们拓扑排序的顺序去划分阶段。

4 动态规划设计方法

4.1 一般方法

一般由初始状态開始。通过对中间阶段决策的选择,达到结束状态。这些决策形成了一个决策序列,同一时候确定了完毕整个过程的一条活动路线。步骤为:

  1. 划分阶段:依照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时。注意划分后的阶段一定要是有序的或者是可排序的。否则问题就无法求解。
  2. 确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。
  3. 确定决策并写出状态转移方程:由于决策和状态转移有着天然的联系。状态转移就是依据上一阶段的状态和决策来导出本阶段的状态。

    所以假设确定了决策,状态转移方程也就可写出。但其实经常是反过来做。依据相邻两段各状态之间的关系来确定决策。

  4. 寻找边界条件:给出的状态转移方程是一个递推式,须要一个递推的终止条件或边界条件。
  5. 程序设计实现:动态规划的主要难点在于理论上的设计。一旦设计完毕,实现部分就会很easy。

4.2 逆向推导

逆向思维法是指从问题目标状态出发倒推回初始状态或边界状态的思维方法。假设原问题能够分解成几个本质同样、规模较小的问题,非常自然就会联想到从逆向思维的角度寻求问题的解决。动态规划与分治法最大的不同在于分解出来的各个子问题的性质不同:

  • 分治法要求各个子问题是独立的(即不包括公共的子问题),因此一旦递归地求出各个子问题的解后,便可自下而上地将子问题的解合并成原问题的解。假设各子问题是不独立的,那么分治法就要做很多不必要的工作,反复地解公共的子问题。
  • 动态规划与分治法的不同之处在于动态规划同意这些子问题不独立(即各子问题可包括公共的子问题),它对每一个子问题仅仅解一次,并将结果保存起来,避免每次碰到时都要反复计算。这就是动态规划高效的一个原因。

动态规划的逆向推导步骤:

  1. 分析最优值的结构。刻画其结构特征;
  2. 递归地定义最优值;
  3. 按自底向上或自顶向下记忆化的方式计算最优值;

4.3 正向推导

正向思维法是指从初始状态或边界状态出发。利用某种规则不断到达新的状态,直到问题目标状态的方法。

动态规划的正向思维法。正是从已知最优值的初始状态或边界状态開始,依照一定的次序遍历整个状态空间,递推出每一个状态所相应问题的最优值。

在正向思维法中。不再区分原问题和子问题,将动态规划的过程看成是从状态到状态的转移。将全部的状态构造出一个状态空间,并在状态空间中设想一个状态网络。若对两个状态i,j,存在决策变量di使t(i,di)=j。则向状态网络加入有向边。

给定己知最优值的初始状态或边界状态,能够沿著有向边推广到未知最优值的新状态。利用状态转移方程得到新状态的状态变量的最优值。

我们能够用这样的方式遍历整个状态空间,得到每一个状态的状态变量的最优值。
动态规划的正向推导步骤:

  1. 构造状态网络;
  2. 依据状态转移关系和状态转移方程建立最优值的递推计算式:
  3. 按阶段的先后次序计算每一个状态的最优值;

动态规划须要按阶段遍历整个状态空间。因此动态规划的效率取决于状态空间的大小和计算每一个状态最优值的开销:假设状态空间的大小是多项式的,那么应用动态规划的算法就是多项式时间的;假设状态空间的大小是指数的,那么应用动态规划的算法也是指数时间的。因此,找一个好的状态划分对动态规划的效率是至关重要的。

5 小实验换零钱问题求解

逆推状态转移方程:数量为 a 的钱换成 n 种硬币的不同方式等于:

  • 数量为 a 的钱换成除第一种硬币外的 n-1 种硬币(必不包括第一种硬币)的不同方式数目加上,
  • 数量为 a-d 的钱(必包括第一种硬币)换成全部硬币种类的不同方式数目。d 为第一种硬币币值

逆推到初始状态:

  • 假设钱为 0 ,说明正好换完成,是一种换零钱方法,
  • 假设钱为负数,或者种类已经递归到 0 种,则说明没有正好换完,不是一种换法,返回0;

还能够正向推导。打表记录已经计算出的值。

Python实现

NUM = 0def count_change(amount, money, kinds):''' 树形递归存在冗余'''global NUMif amount == 0:NUM+=1return 1if amount < 0 or kinds == 0:NUM+=1return 0NUM+=1return count_change(amount, money, kinds - 1) + count_change(amount - money[kinds - 1], money, kinds)def count_dy(amount,money,kinds):'''动态规划,打表记录已经计算的值'''table = [[0 for col in range(kinds)] for row in range(amount+1)]table[0] = [1]*kindsfor i in range(1,amount+1):for j in range(kinds):# 包括 money[j]x = table[i - money[j]][j] if i-money[j] >= 0 else 0# 不包括 money[j]y = table[i][j-1] if j>=1 else 0table[i][j] = x+yreturn table[amount][kinds-1]if __name__ == '__main__':money = [1, 5, 10, 25, 50]print(count_change(100, money, len(money)),'time:',NUM)print(count_dy(100, money, len(money)),'time:',100*len(money))'''
292 time: 15499
292 time: 500
'''

SICP中的Scheme实现(Racket)

【地址:http://blog.csdn.net/thisinnocence/article/details/41073275】

转载于:https://www.cnblogs.com/bhlsheji/p/5176304.html

算法学习笔记(八) 动态规划的一般求解方法相关推荐

  1. 算法学习笔记:网络流#4——ISAP 求解最大流

    算法学习笔记:网络流#4--ISAP 求解最大流 1. 前言 2. 模板 2.1 详解 2.2 正确性证明 2.3 代码 3. 算法对比 3.1 一般数据下的对比 3.2 特殊数据下的对比 4. 总结 ...

  2. 网络流算法学习笔记——最大流问题基本概念和Ford-Fulkerson方法(标号法C++实现)

    屈婉玲<算法设计与分析>第2版第7章网络流算法学习笔记. 基本概念 最大流问题,相当于有从s到t的供水系统,每段路径都有限定流量,除了s.t两地外,每个中间点都不能滞留,从s流入多少,就从 ...

  3. 算法学习笔记----用动态规划解决钢管切割问题

    (说明:由于CSDN的博客中不能添加下标等特殊符号,所以部分内容使用截图的形式) 通过对问题进行高度抽象,现在我们的问题,就是要递归地求解r n 的最大值,下面采用的是一种自顶向下的递归方法: int ...

  4. Python最优化算法学习笔记(Gurobi)

    微信公众号:数学建模与人工智能 github地址:https://github.com/QInzhengk/Math-Model-and-Machine-Learning Python最优化算法学习笔 ...

  5. 基于MVS的三维重建算法学习笔记(四)— 立体匹配经典算法Semi-Global Matching(SGM)论文翻译及要点解读

    基于MVS的三维重建算法学习笔记(四)- 立体匹配经典算法Semi-Global Matching(SGM)论文翻译及要点解读 声明 SGM概述 Cost Calculation(像素代价计算)--M ...

  6. matlab中x从0到5不含0,关于MATLAB的数学建模算法学习笔记

    关于MATLAB的数学建模算法学习笔记 目录 线性规划中应用: (3) 非线性规划: (3) 指派问题;投资问题:(0-1问题) (3) 1)应用fmincon命令语句 (3) 2)应用指令函数:bi ...

  7. 两个字符串的最长公共子序列长度_算法学习笔记(58): 最长公共子序列

    (为什么都更了这么多篇笔记了,这时候才讲这么基础的内容呢?因为我本来以为LCS这种简单的DP不用讲的,结果CF不久前考了LCS的变式,然后我发现由于自己对LCS一点都不熟,居然写不出来 ,于是决定还是 ...

  8. Redis 学习笔记八:集群模式

    Redis 学习笔记八:集群模式 作者:Grey 原文地址: 博客园:Redis 学习笔记八:集群模式 CSDN:Redis 学习笔记八:集群模式 前面提到的Redis 学习笔记七:主从复制和哨兵只能 ...

  9. 数据结构与算法学习笔记15:最大流问题 / 二分图 / 有权无权二分图的匹配 / 匈牙利算法 / 银行家算法 / 稳定婚配

    数据结构与算法学习笔记15:最大流问题 / 二分图 / 有权无权二分图的匹配 / 匈牙利算法 / 银行家算法 / 稳定婚配 引入小题:最短路径 最大流问题(maximum flow problem) ...

  10. 局部线性嵌入LLE算法--学习笔记

    流形学习是一大类基于流形的框架,形象说明流形降维: ISOMAP(更多细节可参考:isomap降维算法--学习笔记_Wsyoneself的博客-CSDN博客): LLE: 和传统的PCA,LDA等关注 ...

最新文章

  1. oracle9i数据库自动备份,Windows环境下Oracle9i数据库文件的自动备份
  2. python stm32-STM32F4系列使用MicroPython开发
  3. json相关,浏览器打开json格式的api接口时,进行格式化,chrome插件
  4. BP算法,用梯度下降法更新权值W与偏置项b
  5. python调用海康威视的摄像头_Python调用海康威视网络相机之——python读取相机rtsp码流显示画面...
  6. Rhino(犀牛)室内模型导入Unity3d快速烘焙光影【2020】
  7. JS获取屏幕宽度高度
  8. 20200229小白自学Python之路00
  9. 单片机位寻址举例_51单片机直接寻址方式与编程举例
  10. Linux系统下安装Adobe Flash Player插件观播放视频
  11. Python程序员必备的四款开发工具
  12. 土豆皮,蒜苗长短,胡萝卜
  13. 不靠广告联盟也能月赚万元
  14. 在网站的地址栏中的显示个性图标
  15. Eclipse插件2
  16. Navicat Premium和Navicat for MySQL的区别
  17. 爱站权重查询 怎么批量查询网站爱站权重
  18. 极客路由 链接密码_极客特惠:计算机,路由器和免费调音
  19. 基于若依开源架构websocket 集成与使用
  20. 基于springboot的在线考试系统的设计与实现 毕业设计毕设参考

热门文章

  1. endnotex7怎么导入中文文献,EndNote 7.0使用中文详细教程
  2. Java与mysql数据库编程中遇见“Before start of result set at com.mysql.jdbc.SQLError.createSQLException” 的解决办法
  3. Linux系统编程 -- 进程与线程之间差别 进程是系统资源分配的最小单位,线程是进程执行的最小单位
  4. 使用Ant定义生成文件
  5. [渝粤教育] 郑州财税金融职业学院 玩转e时代 参考 资料
  6. 【CoRL 2018】通过元策略优化的MBRL算法
  7. [UE4]图片按钮设置技巧
  8. 浅谈欧几里得算法求最大公约数(GCD)的原理及简单应用
  9. 21点游戏java实现
  10. 编程语言-初学者常见的几个问题