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 };

 

posted @ 2018-04-14 22:29  J1ac  阅读(337)  评论(0编辑  收藏  举报