1. 程式人生 > >LintCode 666. 猜數遊戲 II

LintCode 666. 猜數遊戲 II

等於 檢查 you int mon bsp AS 內容 更新

我們正在玩猜數遊戲, 遊戲內容如下:
我在 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