LintCode 666. 猜数游戏 II
Posted J1ac
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LintCode 666. 猜数游戏 II相关的知识,希望对你有一定的参考价值。
我们正在玩猜数游戏, 游戏内容如下:
我在 1到 n 的范围内选择一个数作为待猜的数, 你需要来猜这个数,
每次你猜错的时候, 我会告诉你我选择的这个数是比你说的数要高还是低,
但是, 当你猜这个数为 x 并且猜错的时候你需要支付 $x. 当你猜到我选择的数时, 你将赢得这场游戏
样例
给出 n = 10, 我选择待猜数为 8
第一轮: 你猜测为 5, 我告诉你待猜的值要更大一些. 你需要支付 $5
第二轮: 你猜测为 7, 我告诉你待猜的值要更大一些. 你需要支付 $7
第三轮: 你猜测为 9, 我告诉你待猜的值要更小一些. 你需要支付 $9
游戏结束. 8 是我选择的待猜数.
你最终需要支付 $5 + $7 + $9 = $21
给一个具体的大于等于 1 的数 n, 计算你需要多少钱才可以保证赢.
所以当 n = 10 时, 返回 16.
思路:动态规划,这个猜数游戏可以从小到大进行推广,比如现在我知道的数字所在区间大小为1,比如在[1,1]之中,那么不需要任何付出就能猜到数字,即pay=0;
若数字区间大小为2,比如[n,n+1],我们只需要猜测该数为n,根据结果就能猜中最后的数字,所以我们最多付出pay=n即可猜中数字;
当区间为3,[n,n+2],我们只需猜n+1就一定能直接确定,此时付出为pay = n+1;
...
推广到区间为大小为m+1时,即区间[n,n+m]时可以得到递推式:DP[n][n+m] = min(max(DP[n][x-1],DP[x+1]) + x) 其中n<x<m;
DP[i][j]表示在i-j的数字里面猜中数字所需要的最少付出。
按照这个递推公式使用动态规划就能得到解,最后返回DP[1][n]。
1 class Solution { 2 public: 3 /** 4 * @param n: An integer 5 * @return: how much money you need to have to guarantee a win 6 */ 7 int getMoneyAmount(int n) { 8 // write your code here 9 vector<vector<int>> DP(n+1,vector<int>(n+1,0x7fffffff));//因为后面有一个更新最小值,所以初始化为INT_MAX 10 for(int i = 1; i<n; ++i) {//初始化 11 DP[i][i+1] = i; 12 DP[i][i] = 0; 13 }; 14 DP[n][n] = 0; 15 for(int range = 2; range<n; ++range){//range表示区间大小 16 for(int i = 1;i<n;++i){ 17 if(i+range<=n){//越界检查 18 for(int j = i+1; j<i+range; ++j){ 19 DP[i][i+range] = min(DP[i][i+range],max(DP[i][j-1],DP[j+1][i+range])+j);//参照递推公式 20 } 21 } 22 } 23 } 24 return DP[1][n]; 25 } 26 };
以上是关于LintCode 666. 猜数游戏 II的主要内容,如果未能解决你的问题,请参考以下文章