【数据结构与算法】红蓝球问题:三个人(两人先取红球者胜利,一人捣乱)

题目描述

一共有N个红球,M个蓝球。三个人参与(A,B,C),A,B先取到红球者胜利,两者都没有取到红球,则B胜利。C只取球,不参与胜负。按照A,B,C的次序依次取球。问A胜出的概率。

解题思路

在每次博弈中,A胜出的概率取决于以下三种情况:

  1. A直接取到红球。
  2. A,B依次都取到蓝球,C取到红球,再进入下次博弈,即N-1个红球,M-2个蓝球。
  3. A,B,C依次都取到蓝球,,再进入下次博弈,即N个红球,M-3个蓝球。

显然可以用递归或是动态规划来解题。

测试用例

1 1
样例输出
0.50000

提示
输入样例2
3 4
输出样例2
0.62857

解题代码

  • 动态规划
#include <iostream>
#include <vector>
#include <cstdio>
#include <iomanip>

using namespace std;

float probaOfAWin(int n, int m)
{
    vector<vector<float> > dp(n+1, vector<float>(m+1));
    // 初始化dp
    for(int i = 0; i < n+1; i++)
    {
        // 蓝球为0,则概率为1
        dp[i][0] = 1.0;
    }

    // 红球为0,则概率为0
    for(int i = 0; i < m+1; i++)
        dp[0][i] = 0.0;

    for(int i = 1; i < n+1; i++)
    {
        for(int j = 1; j < m+1; j++)
        {
            // A 直接取到 red
            float A_Red = i * 1.0 / (i + j);
            dp[i][j]  += A_Red;
            
            // A blue and B blue
            float B_Blue = (1-A_Red) * ((j-1) * 1.0 / (i + j-1));

            if(j >= 2)
            {
                // A blue and B blue and C red
                float C_Red = B_Blue * (i * 1.0 / (i + j-2));
                dp[i][j]  += C_Red * dp[i-1][j-2];
            }

            if(j > 2)
            {
                // A blue and B blue and C blue
                float C_Blue = B_Blue * ((j-2) * 1.0 / (i + j-2));
                dp[i][j] += C_Blue * dp[i][j-3];
            }
        }
    }

    return dp[n][m];
    /* 递归:可能细节处理不正确
    if(m == 0 && n != 0)
        return 1;
    if(n == 0)
        return 0;
    int sum = 0;
    // A red
    float A_Red = n * 1.0 / (n + m);
    // B blue
    float B_Blue = (1-A_Red) * ((m-1) * 1.0 / (n + m-1));
    // C red
    float C_Red = B_Blue * (n * 1.0 / (n + m-2));
    // C blue
    float C_Blue = B_Blue * ((m-2) * 1.0 / (n + m-2));

    sum += A_Red + C_Red * probaCore(n-1, m-2) + C_Blue * probaCore(n, m-3);

    return sum;
    */
}

int main()
{
    int n, m;
    cin >> n >> m;

    float res = probaOfAWin(n, m);
    // 格式化输出 1
    printf("%.5f\n", res);
    // 格式化输出 2: 自动补0
    cout.setf(ios::fixed);
    cout << setprecision(5) << res <<endl;  //精度为5,输出5位数
    cout.unsetf(ios::fixed);

    // 格式化输出 3: 自动补0
    cout << fixed;
    cout << setprecision(5) << res <<endl;
    cout.unsetf(ios::fixed);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值