动态规划(Dynamic Programming)(贰)

目录

案例分析

路径总数

最小路径和

背包问题


 

前文链接:动态规划(Dynamic Programming)(壹)

案例分析

路径总数

我们首先分析:这个问题是问从strat这一点到finish这点有多少种方式,那么它的子问题就是从start到任意一点有多少种方式,即dp[ i ] [ j ] ( i 为行 j 为列)。 那么我们假设到(i,j)有n中方式:

 

我们可以发现任意一点到(i , j)只能从(i - 1, j)或者(i , j - 1)这两个点到达,那么我们就可以推出转移方程了。还要注意细节,当机器人在边界时,只有一种方式到达,即 i == 0 || j == 0,都只有一种方式

一:状态定义

创建一个数组dp[][],每个dp[ i ][ j ]的意义就是到达这个点的方式

二:状态间的转移方程

由上述分析可知 dp [ i ] [ j ]  = dp [ i - 1 ] [ j ] + dp [ i ] [ j - 1].

三:状态的初始化

机器人的起始位置是( 0 , 0 ),如果它想到达这个起始点那么必须要有一种方式,否则到不了起始点,题目也就没意义了,所以我们将dp [ 0 ] [ 0 ] 置为1.并且第一行和第一列初值也为1.

四:返回结果

返回dp[ m - 1] [ n - 1 ]

 代码:

public int uniquePaths (int m, int n) {
        // write code here
        int dp[][] = new int[m] [n];
        //初始化第一列为1
        for(int i = 0 ; i < m ; i++){
            dp[i][0] = 1;
        }
        //第一行为1
        for(int j = 0 ; j < n ; j++){
            dp[0][j] = 1;
        }
        for(int i = 1 ; i < m ; i++){
            for(int j = 1 ; j < n ; j++){
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}

在线OJ链接:路径数

最小路径和

这个题目和上一个题目类似,所以我们借用一下上一题的图:

我们知道了到达不是边界的点有两个点,那么求出到达这两个点的最小路径加上这个本身数值。

边界还是一样只有一种方式到达所以加上它前一个的最小路径即可。

一:状态定义

创建一个数组dp[][],每个dp[ i ][ j ]的意义就是到达这个点的最小路径和

二:状态间的转移方程

由上述分析可知 dp [ i ] [ j ]  =Math.min( dp [ i - 1 ] [ j ] + dp [ i ] [ j - 1] ) + array[ i ] [ j ]

三:状态的初始化

第一行和第一列的值都为前一个值加上本身。

四:返回结果

返回dp[ m - 1] [ n - 1 ]

 代码:

public int minPathSum (int[][] grid) {
        // write code here
        int m = grid.length;
        int n = grid[0].length;
        int dp[][] = new int[m][n];
        dp[0][0] = grid[0][0];
        for(int i = 1 ; i < m ; i++){
            dp[i][0] = dp[i-1][0] + grid[i][0]; 
        }
        for(int j = 1 ; j < n ; j++){
            dp[0][j] = dp[0][j-1] + grid[0][j];
        }
        for(int i = 1 ; i < m ; i++){
            for(int j = 1 ; j < n ;j++){
                dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1]) + grid[i][j];
            }
        }
        return dp[m-1][n-1];
    }

 在线OJ链接:最小路径和

背包问题

我们简单分析一波:

如果我们用一维数组,那么dp[ i ]的意义即为前 i 个商品的最大价值,那么dp [ i ] 是否能通过

dp [ i - 1]推导出来呢?当dp [ i - 1 ]已经确定后,对于第 i 个商品,我们有两种操作方式,一种是放进背包,另一种是不放进背包,那么我们就应该确定物体所占空间,因此,一维数组不适用,我们使用二维数组dp[][],dp[ i ] [ j ]代表前 i 个商品 空间为 j 时的最大价值。那么对于每个dp [ i ] [ j ] 就能分出以下三种情况:

我们逐一分析:

---------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------------------------

 

 经过上述三种情况后,我们能够推导出状态转移方程只有两种情况了,因为第一种和第三种重叠了。

一:状态定义

创建一个数组dp[][],每个dp[ i ][ j ]的意义就是前 i 个物品 所占空间 为 j 的最大价值

二:状态间的转移方程

由上述分析可知 dp [ i ] [ j ]有两种情况:

①放入第 i 个物体

dp [ i ] [ j ] = dp [ i - 1 ] [ j - A [ i ] ] + V [ i ];

②不放第 i 个物体

dp [ i ] [ j ] = dp [ i - 1 ] [ j ];

三:状态的初始化

第一行和第一列初值为 0 。

四:返回结果

返回用来记录的最大值

 代码:

public int backPackII(int m, int[] A, int[] V) {
        // write your code here
        int num = A.length;
        if (m == 0 || num == 0)
            return 0;
        //多加一行一列,用于设置初始条件
        int[][] maxValue = new int[num + 1][m + 1];
        //初始化所有位置为0,第一行和第一列都为0,初始条件
        for (int i = 0; i <= num; ++i) {
            maxValue[i][0] = 0;
        }
        for (int i = 1; i <= m; ++i) {
            maxValue[0][i] = 0;
        }
        for (int i = 1; i <= num; ++i) {
            for (int j = 1; j <= m; ++j) {
                //第i个商品在A中对应的索引为i-1: i从1开始
                //如果第i个商品大于j,说明放不下, 所以(i,j)的最大价值和(i-1,j)相同
                if (A[i - 1] > j) {
                    maxValue[i][j] = maxValue[i - 1][j];
                } else {
                    //如果可以装下,分两种情况,装或者不装
                    //如果不装,则即为(i-1, j)
                    //如果装,需要腾出放第i个物品大小的空间:j - A[i-1],
                    //装入之后的最大价值即为(i -1, j - A[i-1]) + 第i个商品的价值V[i - 1]
                    //最后在装与不装中选出最大的价值
                    int newValue = maxValue[i - 1][j - A[i - 1]]
                            + V[i - 1];
                    maxValue[i][j] = Math.max(newValue
                            , maxValue[i - 1][j]);
                }
            }
        } //返回装入前N个商品,物品大小为m的最大价值
        return maxValue[num][m];
}

本文收录专栏《数据结构与算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海绵宝宝养的的小窝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值