又是算概率的问题,和New 21 Game这道题很像,如果我们打算直接用数学的方法来算是不好做的,我们还是要分解成subproblem来解决。假设有w个白豆子,r个红豆子,我们用(w, r)表示这个状态:
- 第一次取豆子之后
- 有w / (w + r)的概率变为(w - 1, r);
- r / (w + r)的概率仍为(w, r)
- 第二次取豆子之后
- 有w / (w + r) * (w - 1) / (w + r - 1)的概率变为(w - 2, r)
- 有w / (w + r) * r / (w + r - 1)的概率变为(w - 1, r - 1)
- 有r / (w + r) * w / (w + r)的概率变为(w - 1, r)
- 有r / (w + r) * r / (w + r)的概率变为(w , r - 1)
一次类推,我们可以用递归的方法求出(1, 0)的概率。这是top-down的思路,如果我们用bottom-up加dp的思路的话。我们用dp[i][j][k]表示第i次操作之后状态变为(j, k)的概率的话,我们有递推公式:
- dp[i][j][k] = dp[i - 1][j + 1][k] * (j + 1) / (j + 1 + k) + dp[i - 1][j][k] * k / (j + k), if i is odd
- dp[i][j][k] = dp[i - 1][j + 1][k] * (j + 1) / (j + 1 + k) + dp[i - 1][j][k + 1] * (k + 1) / (j + k + 1), if i is even
- 注意处理一下边界情况,比如j == w, k == r和i == 0 && j == 0 的情况
因为我们每两次至少可以吃掉一个豆子,所以最多2 * (w + r)次操作之后我们可以吃掉全部的豆子。时间复杂度和空间复杂度为O(w * r * (w + r)),代码如下:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Solution { | |
public: | |
/** | |
* @param w: The W | |
* @param r: The R | |
* @return: The answer | |
*/ | |
double eatTheBeans(int w, int r) { | |
if (!w)return 0; | |
int n = 2 * (w + r); | |
//dp[i][j][k] represent the probability we have j white beans and k red beans left | |
//after step i | |
//dp[i][j][k] = dp[i - 1][j + 1][k] * (j + 1) / (j + 1 + k) + dp[i - 1][j][k] * k / (j + k), if i is odd | |
//dp[i][j][k] = dp[i - 1][j + 1][k] * (j + 1) / (j + 1 + k) + dp[i - 1][j][k + 1] * (k + 1) / (j + k + 1), if i is even | |
vector<vector<vector<double>>> dp(n + 1, vector<vector<double>>(w + 1, vector<double>(r + 1, 0))); | |
dp[0][w][r] = 1.0; | |
for (int i = 1; i <= n; ++i) | |
{ | |
for (int j = w; j >= 0; --j) | |
{ | |
for (int k = r; k >= 0; --k) | |
{ | |
if (j == w && k == r) | |
{ | |
dp[i][j][k] = i % 2 ? dp[i - 1][j][k] * k / (j + k) : 0; | |
continue; | |
} | |
if (j == w) | |
{ | |
dp[i][j][k] = i % 2 ? dp[i - 1][j][k] * k / (j + k) : dp[i - 1][j][k + 1] * (k + 1) / (j + k + 1); | |
continue; | |
} | |
if (k == r) | |
{ | |
dp[i][j][k] = i % 2 ? dp[i - 1][j + 1][k] * (j + 1) / (j + 1 + k) + (!j && !k ? 0 : dp[i - 1][j][k] * k / (j + k)) : | |
dp[i - 1][j + 1][k] * (j + 1) / (j + 1 + k); | |
continue; | |
} | |
dp[i][j][k] = i % 2 ? dp[i - 1][j + 1][k] * (j + 1) / (j + 1 + k) + (!j && !k ? 0 : dp[i - 1][j][k] * k / (j + k)) : | |
dp[i - 1][j + 1][k] * (j + 1) / (j + 1 + k) + dp[i - 1][j][k + 1] * (k + 1) / (j + k + 1); | |
} | |
} | |
} | |
double res = 0; | |
for (int i = 0; i <= n; ++i)res += dp[i][1][0]; | |
return res; | |
} | |
}; |
No comments:
Post a Comment