CXB 红黑牌

题目描述

  你有一个包含R红色和B黑色牌的牌组。

  你正在玩下面的游戏:你洗牌,然后开始逐个处理牌。对于你翻转的每张红牌,你得到一美元,而对于你翻转的每张黑卡,你必须支付1美元。在任何时候(包括比赛的开始),你都可以停下来并保留你的钱。

  给你R和B,你最佳地玩这个游戏你将获得的金额的期望值。

输入输出格式

输入格式

  多组测试数据。

  第一行,一个整数G,表示有G组测试数据。 1 <= G <= 10

  每组测试数据格式: 

      第一行,两个整数,R和 B。 0 <=R,B <= 5000。

输出格式

  共G行,共G行,每行一个实数,误差不超过0.0001。

输入输出样例

输入样例

10

0 7

4 0

5 1

2 2

12 4

11 12

5000 5000

4950 4772

4446 4525

4446 4526

输出样例

0.0

4.0

4.166666666666667

0.6666666666666666

8.324175824175823

1.075642825339958

36.90021846438633

191.15589434419024

8.13249058054577E-4

0.0

题解

  设$dp[i][j]$为剩下$i$红$j$黑时开始进行的期望,易得$dp[i][0]=i,dp[0][i]=0$,继续推,可以得到$dp[i][j]=max((dp[i-1][j]+1) imes frac{i}{i+j}+(dp[i][j-1]-1) imes frac{j}{i+j}, 0)$,直接推就好了。

  注意期望值不一定不能求最大值。

  这里不知道可不可以从r, b开始推,以后再尝试。

#include <iostream>
#include <cstdio>

#define MAX_R (5000 + 5)
#define MAX_B (5000 + 5)

#define RED(i, j) ((dp[(i) - 1][(j)] + 1) * (i) / ((i) + (j)))
#define BLACK(i, j) ((dp[(i)][(j) - 1] - 1) * (j) / ((i) + (j)))

using namespace std;

int G;
int r, b;
double dp[MAX_R][MAX_B];

int main()
{
    scanf("%d", &G);
    while(G--)
    {
        scanf("%d%d", &r, &b);
        dp[0][0] = 0;
        for(register int i = 1; i <= r; ++i)
        {
            dp[i][0] = RED(i, 0);
        }
        for(register int i = 1; i <= b; ++i)
        {
            dp[0][i] = 0;
        }
        for(register int i = 1; i <= r; ++i)
        {
            for(register int j = 1; j <= b; ++j)
            {
                dp[i][j] = max(RED(i, j) + BLACK(i, j), 0.0);
            }
        }
        printf("%lf
", dp[r][b]);
    }
    return 0;
}
参考程序
原文地址:https://www.cnblogs.com/kcn999/p/10627823.html