一、基本概念

动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。

二、基本思想与策略

基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。

由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。

与分治法最大的差别是:适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)。

以上都过于理论,还是看看常见的动态规划问题吧!!!

三、常见动态规划问题

1、找零钱问题

有数组penny,penny中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim(小于等于1000)代表要找的钱数,求换钱有多少种方法。
给定数组penny及它的大小(小于等于50),同时给定一个整数aim,请返回有多少种方法可以凑成aim。
测试样例:
[1,2,4],3,3
返回:2

解析:设dp[n][m]为使用前n中货币凑成的m的种数,那么就会有两种情况:

使用第n种货币:dp[n-1][m]+dp[n-1][m-peney[n]]

不用第n种货币:dp[n-1][m],为什么不使用第n种货币呢,因为penney[n]>m。

这样就可以求出当m>=penney[n]时 dp[n][m] = dp[n-1][m]+dp[n-1][m-peney[n]],否则,dp[n][m] = dp[n-1][m]

代码如下:

  1. <span style="font-size:18px;">import java.util.*;
  2. public class Exchange {
  3. public int countWays(int[] penny, int n, int aim) {
  4. // write code here
  5. if(n==0||penny==null||aim<0){
  6. return 0;
  7. }
  8. int[][] pd = new int[n][aim+1];
  9. for(int i=0;i<n;i++){
  10. pd[i][0] = 1;
  11. }
  12. for(int i=1;penny[0]*i<=aim;i++){
  13. pd[0][penny[0]*i] = 1;
  14. }
  15. for(int i=1;i<n;i++){
  16. for(int j=0;j<=aim;j++){
  17. if(j>=penny[i]){
  18. pd[i][j] = pd[i-1][j]+pd[i][j-penny[i]];
  19. }else{
  20. pd[i][j] = pd[i-1][j];
  21. }
  22. }
  23. }
  24. return pd[n-1][aim];
  25. }
  26. }</span>

2、走方格问题

有一个矩阵map,它每个格子有一个权值。从左上角的格子开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。
给定一个矩阵map及它的行数n和列数m,请返回最小路径和。保证行列数均小于等于100.
测试样例:
[[1,2,3],[1,1,1]],2,3
返回:4

解析:设dp[n][m]为走到n*m位置的路径长度,那么显而易见dp[n][m] = min(dp[n-1][m],dp[n][m-1]);

代码如下:

  1. <span style="font-size:18px;">import java.util.*;
  2. public class MinimumPath {
  3. public int getMin(int[][] map, int n, int m) {
  4. // write code here
  5. int[][] dp = new int[n][m];
  6. for(int i=0;i<n;i++){
  7. for(int j=0;j<=i;j++){
  8. dp[i][0]+=map[j][0];
  9. }
  10. }
  11. for(int i=0;i<m;i++){
  12. for(int j=0;j<=i;j++){
  13. dp[0][i]+=map[0][j];
  14. }
  15. }
  16. for(int i=1;i<n;i++){
  17. for(int j=1;j<m;j++){
  18. dp[i][j] = min(dp[i][j-1]+map[i][j],dp[i-1][j]+map[i][j]);
  19. }
  20. }
  21. return dp[n-1][m-1];
  22. }
  23. public int min(int a,int b){
  24. if(a>b){
  25. return b;
  26. }else{
  27. return a;
  28. }
  29. }
  30. }</span>

3、走台阶问题

有n级台阶,一个人每次上一级或者两级,问有多少种走完n级台阶的方法。为了防止溢出,请将结果Mod 1000000007
给定一个正整数int n,请返回一个数,代表上楼的方式数。保证n小于等于100000。
测试样例:
1
返回:1

解析:这是一个非常经典的为题,设f(n)为上n级台阶的方法,要上到n级台阶的最后一步有两种方式:从n-1级台阶走一步;从n-1级台阶走两步,于是就有了这个公式f(n) = f(n-1)+f(n-2);

代码如下:

  1. <span style="font-size:18px;">import java.util.*;
  2. public class GoUpstairs {
  3. public int countWays(int n) {
  4. // write code here
  5. if(n<=2)
  6. return n;
  7. int f = 1%1000000007;
  8. int s = 2%1000000007;
  9. int t = 0;
  10. for(int i=3;i<=n;i++){
  11. t = (f+s)%1000000007;
  12. f = s;
  13. s = t;
  14. }
  15. return t;
  16. }
  17. }</span>

4、最长公共序列数

给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最长公共子序列。
给定两个字符串A和B,同时给定两个串的长度n和m,请返回最长公共子序列的长度。保证两串长度均小于等于300。
测试样例:
"1A2C3D4B56",10,"B1D23CA45B6A",12
返回:6

解析:设dp[n][m] ,为A的前n个字符与B的前m个字符的公共序列长度,则当A[n]==B[m]的时候,dp[i][j] = max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]),否则,dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);

代码如下:

    1. <span style="font-size:18px;">import java.util.*;
    2. public class LCS {
    3. public int findLCS(String A, int n, String B, int m) {
    4. // write code here
    5. int[][] dp = new int[n][m];
    6. char[] a = A.toCharArray();
    7. char[] b = B.toCharArray();
    8. for(int i=0;i<n;i++){
    9. if(a[i]==b[0]){
    10. dp[i][0] = 1;
    11. for(int j=i+1;j<n;j++){
    12. dp[j][0] = 1;
    13. }
    14. break;
    15. }
    16. }
    17. for(int i=0;i<m;i++){
    18. if(a[0]==b[i]){
    19. dp[0][i] = 1;
    20. for(int j=i+1;j<m;j++){
    21. dp[0][j] = 1;
    22. }
    23. break;
    24. }
    25. }
    26. for(int i=1;i<n;i++){
    27. for(int j=1;j<m;j++){
    28. if(a[i]==b[j]){
    29. dp[i][j] = max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]);
    30. }else{
    31. dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
    32. }
    33. }
    34. }
    35. return dp[n-1][m-1];
    36. }
    37. public int max(int a,int b,int c){
    38. int max = a;
    39. if(b>max)
    40. max=b;
    41. if(c>max)
    42. max = c;
    43. return max;
    44. }
    45. }</span>

动态规划算法(后附常见动态规划为题及Java代码实现)的更多相关文章

  1. JVM组成、GC回收机制、算法、JVM常见启动参数、JAVA出现OOM,如何解决、tomcat优化方法

    JVM组成.GC回收机制.算法.JVM常见启动参数.JAVA出现OOM,如何解决.tomcat优化方法

  2. 排序算法对比,步骤,改进,java代码实现

    前言 发现是时候总结一番算法,基本类型的增删改查的性能对比,集合的串并性能的特性,死记太傻了,所以还是写在代码里,NO BB,SHOW ME THE CODE! github地址:https://gi ...

  3. 多线程动态规划算法求解TSP(Traveling Salesman Problem) 并附C语言实现例程

    TSP问题描述: 旅行商问题,即TSP问题(Travelling Salesman Problem)又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须 ...

  4. 动态规划算法(Dynamic Programming,简称 DP)

    动态规划算法(Dynamic Programming,简称 DP) 浅谈动态规划 动态规划算法(Dynamic Programming,简称 DP)似乎是一种很高深莫测的算法,你会在一些面试或算法书籍 ...

  5. 动态规划算法详解 Dynamic Programming

    博客出处: https://blog.csdn.net/u013309870/article/details/75193592 前言 最近在牛客网上做了几套公司的真题,发现有关动态规划(Dynamic ...

  6. 算法导论——lec 11 动态规划及应用

    和分治法一样,动态规划也是通过组合子问题的解而解决整个问题的.分治法是指将问题划分为一个一个独立的子问题,递归地求解各个子问题然后合并子问题的解而得到原问题的解.与此不同,动态规划适用于子问题不是相互 ...

  7. 以计算斐波那契数列为例说说动态规划算法(Dynamic Programming Algorithm Overlapping subproblems Optimal substructure Memoization Tabulation)

    动态规划(Dynamic Programming)是求解决策过程(decision process)最优化的数学方法.它的名字和动态没有关系,是Richard Bellman为了唬人而取的. 动态规划 ...

  8. 五大常用算法之二:动态规划算法(DP)

    一.基本概念 动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移.一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划. 二.基本思想与策略 基本 ...

  9. 『嗨威说』算法设计与分析 - 动态规划思想小结(HDU 4283 You Are the One)

    本文索引目录: 一.动态规划的基本思想 二.数字三角形.最大子段和(PTA)递归方程 三.一道区间动态规划题点拨升华动态规划思想 四.结对编程情况 一.动态规划的基本思想: 1.1 基本概念: 动态规 ...

随机推荐

  1. 如何计算android设备的屏幕物理尺寸

    https://segmentfault.com/q/1010000002794179 通过android提供的接口,我们可以获取到如下的信息:int densityDpi = mContext.ge ...

  2. 【Head First Servlets and JSP】笔记12:URL重写

    1.会话管理的核心在于“交换会话ID”,来回传递cookie是最简单的方法,容器通过客户端发来的JSSESIONID查找匹配的对话. 2.如果浏览器禁用了cookie,那就意味着浏览器将忽略响应首部中 ...

  3. juniper ssg 常用命令

    netscreen juniper ssg操作命令   2013年4月10日   命令行下取得配置信息 get config   命令行下取得相应时间设置 get clock    set vrout ...

  4. 最长k可重区间集

      P3358 最长k可重区间集问题 P3357 最长k可重线段集问题 P3356 火星探险问题 P4012 深海机器人问题 P3355 骑士共存问题 P2754 [CTSC1999]家园 题目描述 ...

  5. (转)理解Keystone的四种Token

    Token 是什么 通俗的讲,token 是用户的一种凭证,需拿正确的用户名/密码向 Keystone 申请才能得到.如果用户每次都采用用户名/密码访问 OpenStack API,容易泄露用户信息, ...

  6. VS2010 + QT 5 +open inventor 环境配置

    本科毕业设计做的是   随钻测量的井眼轨迹和测井曲线的三维显示  要求的环境是  QT +  Open Inventor    在寒假开学前,打算将环境配置好,开学后再正式编码实现,可是....环境也 ...

  7. 2016-02-20WebForm登陆验证,判断用户是否登陆 PageBase类

    http://blog.csdn.net/fanbin168/article/details/49404233 很多时候,WebFrom页面,我们需要判断用户是否已经登陆了.假如有很多页面,难道我们要 ...

  8. c++中对齐方式

    使用cout<<setiosflags(ios::right)以后, 再调用 cout<<setiosflags(ios::left);无效的, 你可以在调用之前加上一句 co ...

  9. 51nod 1099 贪心/思维

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1099 1099 任务执行顺序 基准时间限制:1 秒 空间限制:13107 ...

  10. RK30SDK开发板驱动分析(一):platform device 的概念与注册

    做过51单片机或者ARM开发的人都知道,单片机内部都有自己的“片内外设”,比如UART,比如I2C,比如SPI等等... 写单片机程序的时候,比如对于UART的驱动,我们都是在程序中直接写一套函数,来 ...