0
点赞
收藏
分享

微信扫一扫

动态规划DP算法理解

其生 2022-01-05 阅读 139

1. DP算法定义:

每次决策依赖于当前状态,又随即引起状态的转移,多阶段最优化决策解决问题的过程就称为动态规划。

2. DP算法基本流程:

初始状态→│决策1│→│决策2│→…→│决策n│→结束状态

1、划分:按照问题的特征,把问题分为若干阶段。注意:划分后的阶段一定是有序的或者可排序的

2、确定状态和状态变量:将问题发展到各个阶段时所处的各种不同的客观情况表现出来。状态的选择要满足无后续性

3、确定决策并写出状态转移方程:状态转移就是根据上一阶段的决策和状态来导出本阶段的状态。根据相邻两个阶段状态之间的联系来确定决策方法和状态转移方程

4、边界条件:状态转移方程是一个递推式,因此需要找到递推终止的条件

DP算法实现三要素:

1、问题的阶段

2、每个阶段的状态

3、相邻两个阶段之间的递推关系

确定了动态规划的这三要素,整个求解过程就可以用一个最优决策表来描述,最优决策表是一个二维表,其中行表示决策的阶段,列表示问题状态,表格需要填写的数据一般对应此问题的在某个阶段某个状态下的最优值(如最短路径,最长公共子序列,最大价值等),填表的过程就是根据递推关系,从1行1列开始,以行或者列优先的顺序,依次填写表格,最后根据整个表格的数据通过简单的取舍或者运算求得问题的最优解。

例如:f(n,m)=max{f(n-1,m), f(n-1,m-w[n])+P(n,m)}

3. DP常见问题:

1、找零钱问题   

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

测试样例:
penny=[1,2,4]

penny_size=3

aim = 3
返回:2
即:方案为{1,1,1}和{1,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][m-peney[n]],

  否则,dp[n][m] = dp[n-1][m]。

import java.util.*;  
public class Exchange {  
    public int countWays(int[] penny, int n, int aim) {  
        // write code here  
        if(n==0||penny==null||aim<0){  
         return 0;     
        }  
        int[][] pd = new int[n][aim+1];  
        for(int i=0;i<n;i++){  
         pd[i][0] = 1;     
        }  
        for(int i=1;penny[0]*i<=aim;i++){  
         pd[0][penny[0]*i] = 1;     
        }  
        for(int i=1;i<n;i++){  
            for(int j=0;j<=aim;j++){  
                if(j>=penny[i]){  
                    pd[i][j] = pd[i-1][j]+pd[i][j-penny[i]];  
                }else{  
                    pd[i][j] = pd[i-1][j];  
                }  
            }  
        }  
        return pd[n-1][aim];  
    }

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]);

import java.util.*;    
public class MinimumPath {  
    public int getMin(int[][] map, int n, int m) {  
        // write code here  
       int[][] dp = new int[n][m];  
        for(int i=0;i<n;i++){  
            for(int j=0;j<=i;j++){  
             dp[i][0]+=map[j][0];      
            }  
        }  
        for(int i=0;i<m;i++){  
            for(int j=0;j<=i;j++){  
             dp[0][i]+=map[0][j];      
            }  
        }  
        for(int i=1;i<n;i++){  
            for(int j=1;j<m;j++){  
             dp[i][j] = min(dp[i][j-1]+map[i][j],dp[i-1][j]+map[i][j]);     
            }  
        }  
        return dp[n-1][m-1];  
    }  
    public int min(int a,int b){  
        if(a>b){  
         return b;     
        }else{  
         return a;     
        }  
    }
举报

相关推荐

0 条评论