目录
前文链接:动态规划(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];
}
本文收录专栏《数据结构与算法》