We are playing the Guess Game. The game is as follows:
I pick a number from 1 to n. You have to guess which number I picked.
Every time you guess wrong, I'll tell you whether the number I picked is higher or lower.
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 guess 5, I tell you that it's higher. You pay $5. Second round: You guess 7, I tell you that it's higher. You pay $7. Third round: You guess 9, 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.
Given a particular n ≥ 1, find out how much money you need to have to guarantee a win.
【问题分析】
1、该问题的意思是给定一个数字n,从1到n中取一个数字,让另外一个人猜结果
如果对方猜错,我会告诉对方实际数字比他猜的更大,还是更小
同时本次猜错的代价为猜错的这个数字
求解:为了确保肯定能才对,需要付出的最小代价
2、 注意到这里的最小代价有一个前提,就是一定能猜对
这是问题可以采用动态规划求解,现给出dp[i][j]定义,然后介绍
dp[i][j]表示在i和j之间猜测时肯定能赢的最小代价
从1到n中猜测可以分为两部分,如果猜测结果为k,也就是k确定了,那么猜错的代价为:
情况1:如果真实值大于猜测值,代价为k加上k+1到n猜测的代价,因为下一步是要在k+1到n之间猜测
情况2:如果真实值小于猜测值,代价为k加上1到k-1猜测的代价,因为下一步是要在1到k-1之间猜测
想要肯定能猜对,那么必须从情况1和情况2中选择猜测代价最大的一种情况
cost_k = k + max(dp[i][k-1], dp[k+1][j])
当在i和j之间猜测时,也就是i和j确定了,k有多种可能
上面说从情况1和情况2中选择猜测代价最大的情况,就是在k给定的情况下,选择猜测代价最大的情况,
现在k变化时,不同的k有不同的最大代价,为了尽可能少付出代价,需要选择所有k情况下,代价最小的结果
作为i到j之间猜测的肯定能赢的最小代价
cost_i_j =min(cost_k), i < k < j
因此dp[1][n]即为1到n之间猜测时,肯定能赢的最小代价
【AC代码】
class Solution {
public:
int getMoneyAmount(int n) {
std::vector<std::vector<int> > dp(n+2, std::vector<int>(n+2, 0));
for (int right = 1; right <= n; ++right) {
for (int left = right-1; left >= 1; --left) {
int min_val = INT_MAX;
for ( int mid = left; mid <= right; ++mid) {
int tmp = mid + std::max(dp[left][mid-1], dp[mid+1][right]);
min_val = std::min(min_val, tmp);
}
dp[left][right] = min_val;
}
}
return dp[1][n];
}
};
参考资料:
https://discuss.leetcode.com/topic/51370/c-more-simple-dp-solution/2