• Leetcode808. 分汤



    题目链接

    点我(^_^)


    题目大意

    注意不是两个概率加和除以2


    解题思路

    考虑动态规划,因为汤的分配都是以 25 的倍数进行分配的,所以这里把 25 ml 的汤看作一份, 总 的 份 数 = ⌈ 汤 的 体 积 / 25 ⌉ 总的份数 = \left \lceil 汤的体积/25 \right \rceil =/25,比如 101 ml 的汤可以看作 5 份。

    d p [ i ] [ j ] dp[i][j] dp[i][j] 表示在 A 类型汤剩余 i i i 份,B 类型汤剩余 j j j 时,汤A 先分配完的概率 + 汤A和汤B 同时分配完的概率 / 2。那么其递推公式如下,就是分别执行四种分配操作。

    d p [ i ] [ j ] = d p [ i − 4 ] [ j ] + d p [ i − 3 ] [ j − 1 ] + d p [ i − 2 ] [ j − 2 ] + d p [ i − 1 ] [ j − 3 ] 4 dp[i][j]=\frac{dp[i-4][j]+dp[i-3][j-1]+dp[i-2][j-2]+dp[i-1][j-3]}{4} dp[i][j]=4dp[i4][j]+dp[i3][j1]+dp[i2][j2]+dp[i1][j3]

    下面考虑起始状态:

    • d p [ 0 ] [ 0 ] = 0.5 dp[0][0]=0.5 dp[0][0]=0.5 此时 汤A和汤B 同时分配完的概率为 1,除以 2 之后就是 0.5。
    • d p [ i ] [ 0 ] = 0 dp[i][0]=0 dp[i][0]=0 此时 汤B 先被分配完的概率为 1,那么其他情况概率就是 0。
    • d p [ 0 ] [ j ] = 0 dp[0][j]=0 dp[0][j]=0 此时 汤A 先被分配完的概率为 1。

    此时时间复杂度为 O(n2/125),肯定是不行的, 我们可以发现,每次分配操作有 (4,0),(3,1),(2,2),(1,3) 四种,那么在一次分配中,汤 A 平均会被分配的份数期望为 E(A)=(4+3+2+1)×0.25=2.5,汤 B 平均会被分配的份数期望为 E(B)=(0+1+2+3)×0.25=1.5。因此在 n 非常大的时候,汤 A 会有很大的概率比 B 先分配完,汤 A 被先取完的概率应该非常接近 1。事实上,当我们进行实际计算时发现,当 n≥4475 时,所求概率已经大于0.99999了(可以通过上面的动态规划方法求出),它和 1 的误差(无论是绝对误差还是相对误差)都小于 10−5

    实际我们在进行测算时发现:

    因此在 n ≥ 179 × 25 n \ge 179 \times 25 n179×25 时,我们只需要输出 1 作为答案即可。在其它的情况下,我们使用动态规划计算出答案。

    当然,也可以使用记忆化搜索,这时可以省去计算某些不必要的状态。


    代码(C++)

    动态规划

    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];
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    记忆化搜索

    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    java计算机毕业设计基于springboot 垃圾回收分类网站
    Ubuntu 软件包管理工具 —— dkpg、apt(dpkg常用指令、apt 软件源的配置)
    PVE系列教程(十六)、安装ubuntu server22.04系统
    Python实现KNN(K近邻)分类模型(KNeighborsClassifier算法)并应用网格搜索算法寻找最优参数值以及数据标准化均衡化项目实战
    【2. IIC】
    微信小程序去除默认滚动条展示
    JS进阶-垃圾回收机制和算法
    React事件与原生DOM事件的不同
    开发常用的 Linux 命令知识积累
    python自动化测试(3)- 自动化框架及工具
  • 原文地址:https://blog.csdn.net/weixin_44491423/article/details/127964954