zoukankan      html  css  js  c++  java
  • 动态规划算法(后附常见动态规划为题及Java代码实现)

    一、基本概念

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

    二、基本思想与策略

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

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

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

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

    三、常见动态规划问题

       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]

    代码如下:

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

    代码如下:

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

    代码如下:

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

    代码如下:

    [java] view plain copy
     
      1. <span style="font-size:18px;">import java.util.*;  
      2.   
      3. public class LCS {  
      4.     public int findLCS(String A, int n, String B, int m) {  
      5.         // write code here  
      6.         int[][] dp = new int[n][m];  
      7.         char[] a = A.toCharArray();  
      8.         char[] b = B.toCharArray();  
      9.        for(int i=0;i<n;i++){  
      10.            if(a[i]==b[0]){  
      11.                dp[i][0] = 1;  
      12.                for(int j=i+1;j<n;j++){  
      13.                    dp[j][0] = 1;  
      14.                }  
      15.                break;  
      16.            }  
      17.              
      18.        }  
      19.          for(int i=0;i<m;i++){  
      20.            if(a[0]==b[i]){  
      21.                dp[0][i] = 1;  
      22.                for(int j=i+1;j<m;j++){  
      23.                    dp[0][j] = 1;  
      24.                }  
      25.                break;  
      26.            }  
      27.              
      28.        }  
      29.        for(int i=1;i<n;i++){  
      30.            for(int j=1;j<m;j++){  
      31.                if(a[i]==b[j]){  
      32.                   dp[i][j] = max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]);  
      33.                }else{  
      34.                    dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);  
      35.                }  
      36.                      
      37.            }  
      38.        }   
      39.           
      40.         return dp[n-1][m-1];  
      41.     }  
      42.     public int max(int a,int b,int c){  
      43.         int max = a;  
      44.         if(b>max)  
      45.             max=b;  
      46.         if(c>max)  
      47.             max = c;  
      48.         return max;  
      49.     }  
      50. }</span>  
  • 相关阅读:
    【BZOJ 4151 The Cave】
    【POJ 3080 Blue Jeans】
    【ZBH选讲·树变环】
    【ZBH选讲·拍照】
    【ZBH选讲·模数和】
    【CF Edu 28 C. Four Segments】
    【CF Edu 28 A. Curriculum Vitae】
    【CF Edu 28 B. Math Show】
    【CF Round 439 E. The Untended Antiquity】
    【CF Round 439 C. The Intriguing Obsession】
  • 原文地址:https://www.cnblogs.com/yangchunchun/p/7265699.html
Copyright © 2011-2022 走看看