1、动态规划法
我们可以利用二维数组 d p [ i ] [ j ] dp[i][j] dp[i][j]来记录当汤A的体积为i,汤B的体积为j时的概率。由于体积均为25的倍数,为了方便计算我们可以将所有体积都除以25。由于误差范围为 1 0 − 5 10^{-5} 10−5,我们可以计算得出当$n\ge179时,比值和1的差值小于 1 0 − 5 10^{-5} 10−5,我们可以直接返回1。
class Solution {
public:
double soupServings(int n) {
n = ceil((double) n / 25);
if (n >= 179) {
return 1.0;
}
vector<vector<double>> dp(n + 1, vector<double>(n + 1));
dp[0][0] = 0.5;
for (int i = 1; i <= n; i++) {
dp[0][i] = 1.0;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = (dp[max(0, i - 4)][j] + dp[max(0, i - 3)][max(0, j - 1)] +dp[max(0, i - 2)][max(0, j - 2)] + dp[max(0, i - 1)][max(0, j - 3)]) / 4.0;
}
}
return dp[n][n];
}
};
2、记忆化搜索
与动态规划法相同,我们可以使用记忆化搜索,使用数组 d p [ i ] [ j ] dp[i][j] dp[i][j]来保留当前的比值。其优点在于自底向上的搜索可以避免许多不可能的状态。
class Solution {
public:
double soupServings(int n) {
n = ceil((double) n / 25);
if (n >= 179) {
return 1.0;
}
memo = vector<vector<double>>(n + 1, vector<double>(n + 1));
return dfs(n, n);
}
double dfs(int a, int b) {
if (a <= 0 && b <= 0) {
return 0.5;
} else if (a <= 0) {
return 1;
} else if (b <= 0) {
return 0;
}
if (memo[a][b] > 0) {
return memo[a][b];
}
memo[a][b] = 0.25 * (dfs(a - 4, b) + dfs(a - 3, b - 1) +
dfs(a - 2, b - 2) + dfs(a - 1, b - 3));
return memo[a][b];
}
private:
vector<vector<double>> memo;
};