题目大意:
https://leetcode-cn.com/problems/guess-number-higher-or-lower-ii
我们正在玩一个猜数游戏,游戏规则如下:
我从 1 到 n 之间选择一个数字。
你来猜我选了哪个数字。
如果你猜到正确的数字,就会 赢得游戏 。
如果你猜错了,那么我会告诉你,我选的数字比你的 更大或者更小 ,并且你需要继续猜数。
每当你猜了数字 x 并且猜错了的时候,你需要支付金额为 x 的现金。如果你花光了钱,就会 输掉游戏 。
给你一个特定的数字 n ,返回能够 确保你获胜 的最小现金数,不管我选择那个数字 。
样例1的例图
输入:n = 10 输出:16
输入:n = 1 输出:0
输入:n = 2 输出:1
提示:
1 <= n <= 200
解题报告:
这个问题也可以看成是一个博弈问题,但其实是:让你做出一步决策,然后考虑最差情况即可。换句话说:做出的每一步决策是主动的,然后面临的状况中要考虑最差的局面,在做出下一次决策。看似可以二分,但是无法证明这种决策方法的正确性,最保险的方法就是枚举所有状态,然后发现状态是可以dp的。dp[i][j]代表当前决策区间是[i,j]时的最小花费,然后按照区间dp的方式更新dp数组就可以了。
内层k枚举每一个决策,注意不要忘记了边界情况:枚举i和j这两个端点。
AC代码:
class Solution {
public:int max(int a, int b) {return a>b?a:b;}int min(int a, int b) {return a<b?a:b;}int getMoneyAmount(int n) {vector<vector<int>> dp(n+1,vector<int>(n+1));for(int len = 1; len<n; len++) {for(int l = 1; l<=n-len; l++) {int r = l+len;dp[l][r] = min(l + dp[l+1][r], r + dp[l][r-1]);for(int k = l+1; k<=r-1; k++) {dp[l][r] = min(dp[l][r], max(dp[l][k-1], dp[k+1][r]) + k);}}}return dp[1][n];}
};