题目
思路:
-----分析:
- 猜数字的过程中需满足确保获胜且最小现金
- 无论猜那个数都得满足1. 中的条件,于是不能使用二分,我们必须对所有情况进行决策
- 确定最优子结构:当只有两个数时,选取两个数都可确保获胜,但选小的那个,能满足最小现金
- 将最优子结构状态转移至全局,在1~n中选取一个数,两边都得是最优子结构,再在子结构中选取最优解
- 确定状态转移方程dp[i][j]=Math.min(dp[i][j],k+Math.max(dp[i][k-1],dp[k+1][j]));
-----注意:
- 通过递推方程,我们知道dp[i][j]是由子区间确定的,我们必须得确定子区间的值,例如我们若想要知道dp[1][3] 我们 必须得知道dp(1,2),dp(2,3), 当然,你可以先求dp(1,2),再求dp(2,3)也可先求dp(2,3)和dp(1,2)
- 下面给出两种(从后往前,从前往后)求出子结构,最后求出整个结构的最优的方式
代码:
class Solution {
public int getMoneyAmount(int n) {
// dp[i][j] 表示从i,j中取出确保获胜的最小现金数
int[][] dp=new int[n+1][n+1];
//由于当前问题可以拆分成若干个子问题(猜了一个数,再从剩余数中获取确保获胜且最小)
// 最后模拟出dp[1][n]
// 方式一
// for(int i=n-1;i>=1;i--){
// for(int j=i+1;j<=n;j++){
// //枚举出所有子区间
// dp[i][j]=Integer.MAX_VALUE;
// for(int k=i;k<j;k++){
// //每个区间都选一个数
// dp[i][j]=Math.min(dp[i][j],k+Math.max(dp[i][k-1],dp[k+1][j]));
// }
// }
// }
//方式二
for(int j=1;j<=n;j++){
for(int i=j-1;i>=1;i--){
dp[i][j]=Integer.MAX_VALUE;
for(int k=i;k<j;k++){
dp[i][j]=Math.min(dp[i][j],k+Math.max(dp[i][k-1],dp[k+1][j]));
}
}
}
return dp[1][n];
}
}