链接:https://leetcode-cn.com/problems/guess-number-higher-or-lower-ii/
我们正在玩一个猜数游戏,游戏规则如下:
我从 1 到 n 之间选择一个数字,你来猜我选了哪个数字。
每次你猜错了,我都会告诉你,我选的数字比你的大了或者小了。
然而,当你猜了数字 x 并且猜错了的时候,你需要支付金额为 x 的现金。直到你猜到我选的数字,你才算赢得了这个游戏。
示例:
n = 10, 我选择了8.
第一轮: 你猜我选择的数字是5,我会告诉你,我的数字更大一些,然后你需要支付5块。
第二轮: 你猜是7,我告诉你,我的数字更大一些,你支付7块。
第三轮: 你猜是9,我告诉你,我的数字更小一些,你支付9块。
游戏结束。8 就是我选的数字。
你最终要支付 5 + 7 + 9 = 21 块钱。
给定 n ≥ 1,计算你至少需要拥有多少现金才能确保你能赢得这个游戏。
动态规划,但是真的难想。模仿他人题解写的,记录一下吧,反正要是有公司笔试考这题我就直接交卷。。
1 class Solution { 2 public: 3 int getMoneyAmount(int n) { 4 vector<vector<int>>dp(n+1,vector<int>(n+1,0)); 5 dp[1][1]=0; 6 int _min; 7 //对于i到j的数字,如果我们先猜k(i<k<j),得能保证赢得游戏。 8 //那么需要假设k是错的,取[i,k-1]和[k+1,j]需要更多钱来保证赢的那个,设为bigger 9 //则第一次猜k的最小需求金额就是k+bigger 10 //对于所有可能的k,都要遍历一遍 11 //最大的那一组k+bigger就是对于i到j的数字序列我们能保证赢得游戏的最小需求金额。 12 13 //由于dp[i][j]表示给定i到j的序列,我们要赢得游戏所需最少现金 14 //需要从中取i<k<j,即为了求dp[i][j],我们需要知道dp[i][k-1]和dp[k+1][j]。 15 //可以发现要先求行数更大的行以及更小的列,所以选择从下到上,从左到右计算dp数组 16 for(int i=n;i>=1;--i){ 17 dp[i][i]=0; 18 for(int j=i+1;j<=n;++j){ 19 _min=INT_MAX; 20 for(int k=i+1;k<j;++k){ 21 _min=min(_min,k+max(dp[i][k-1],dp[k+1][j])); 22 } 23 _min=min(_min,i+dp[i+1][j]); 24 _min=min(_min,dp[i][j-1]+j); 25 dp[i][j]=_min; 26 } 27 } 28 return dp[1][n]; 29 } 30 };
原文:https://www.cnblogs.com/FdWzy/p/12375566.html