Weare playing the Guess Game. The game is as follows:
Ipick a number from 1 to n.You have to guess which number I picked.
Everytime you guess wrong, I'll tell you whether the number I picked is higher orlower.
However,when you guess a particular number x, and you guess wrong, you pay $x.You win the game when you guess the number I picked.
Example:
n = 10, I pick 8.
First round: You guess5, I tell you that it's higher. You pay $5.
Second round: You guess 7, I tell you that it's higher. Youpay $7.
Third round: You guess9, I tell you that it's lower. You pay $9.
Game over. 8 is the number I picked.
You end up paying $5 + $7 + $9 = $21.
Givena particular n ≥ 1,find out how much money you need to have to guarantee a win.
Credits:
Special thanks to @agave and @StefanPochmann for adding this problem and creating all test cases.
一开始题想的是使用分治法,但是后来一想这样肯定不对,然后又考虑到深度优先遍历,这样虽然可以得到正确的结果,但是花费的时间肯定很长,然后又考虑到线型dp, 想来想去还是得不到正确的结果,最后考虑树状dp,递推公式是
mid = (s + right) / 2;
dpLeft = dp[s][mid - 1];
dpRight = dp[mid+1][right];
min = max(dpRight,dpLeft) + mid;
dp[s][right] = min;
但是这样的话可能有一些正确结果会漏过,所以mid需要继续往右,也就是mid++,然后重新判断dpleft和dpRight,如果if (dpRight + mid< min) min = dpRight + mid; 持续这种判断直到dpLeft >= dpRight,然后min = max(dpRight,dpLeft) + mid; dp[s][right] = min;,这样就能得到正确的dp[s][right]
class Solution {
public:
int getMoneyAmount(int n) {
vector<vector<int>> dp(n+2,vector<int>(n+2, 0));
int mid,right;
for (int l = 2; l <= n; l++)
{
for (int s = 1; s <= n - l + 1;s++)
{
int min;
right = s + l - 1;
mid = (s + right) / 2;
int dpLeft; int dpRight;
dpLeft = dp[s][mid - 1];
dpRight = dp[mid+1][right];
min = dpRight + mid;
while (dpLeft < dpRight) {
if (dpRight + mid <min)
min = dpRight +mid;
mid++;
dpLeft = dp[s][mid - 1];
dpRight = dp[mid +1][right];
}
if (dpLeft + mid < min)
min = dpLeft + mid;
dp[s][right] = min;
}
}
return dp[1][n];
}
};