题目描述
你有一个包含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; }