1.礼物的最大价值问题
礼物的最大价值
题目描述:在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
解法:动态规划
假设 dp[i][j] 表示走到格子 (i, j) 的礼物最大累计价值,则 dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1]。
代码:
class Solution {
public int maxValue(int[][] grid) {
int m = grid.length, n = grid[0].length;
int[][] dp = new int[m + 1][n + 1];
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1];
}
}
return dp[m][n];
}
}
2.母牛生产问题
假设农场中成熟的母牛每年都会生 1 头小母牛,并且永远不会死。第一年有 1 只小母牛,从第二年开始,母牛开始生小母牛。每只小母牛 3 年之后成熟又可以生小母牛。给定整数 N,求 N 年后牛的数量。
解法:动态规划
建立动态方程:第i年的母牛数等于第i-1年的母牛数加上三年前的母牛数,因为三年前的小牛今年都会生产一头小牛,每年生一个。所以动态方程为:dp[ i ]=dp[ i-1 ]+dp[ i-3 ]
解释如下 :因为dp[i-1]中包含的牛分为三类:
- 第一类:之前一直成熟的母牛
- 第二类:还未成熟的母牛,并且第i年也不会成熟
- 第三类:还未成熟的母牛,但第i年就会成熟
因此,第一类+第三类牛(因为牛三年成熟,所以此即为第i-3年的牛数)加上dp[ i-1 ]的牛数就等于dp[ i ]
代码:
public int cowNums(int n){
if(n<=3){
return n;
}
int[] dp = new int[n+1];
dp[0] = 0;
dp[1] = 1;
dp[2] = 2;
dp[3] = 3;
for(int i = 4;i<=n;i++){
dp[i] = dp[i-1]+dp[i-3];
}
return dp[n];
}
3.信件错排问题
题目描述:有n个信和信封,求错误装信方式的数量(所有信封都没有装各自的信)。
解法:动态规划
假设dp[i-1]是前i-1个信和信封,错误装信方式的数量,则对于第i个信和信封,只需要把信与前面任何一封信j交换一下,就可以得到一个满足条件的结果。因此确定dp[i-1] * (i-1)
同时,如果前面的一封信 j 在其正确的信封上,而另外i-2封信都在不同的信封上,那么,把信 j 和信 i 交换,也可以得到满足条件的结果。因此确定dp[i-2] * (i-1)
因此,状态转移方程是:
dp[i] = dp[i-1](i-1)+dp[i-2](i-1)
public int solution(n){
int[] dp = new int[n+1];
if(n<=2){
return n-1;
}
dp[1] = 0;
dp[2] = 1;
for(int i = 3;i<=n;++i){
dp[i] = dp[i-1]*(i-1)+dp[i-2]*(i-1);
}
return dp[n];
}