您的位置:首页 > 编程语言 > Go语言

Red is good (DP)

2017-03-20 21:17 405 查看

题目

Problem Description

桌面上有R张红牌和B张黑牌,随机打乱顺序后放在桌面上,开始一张一张地翻牌,翻到红牌得到1美元,黑牌则付出1美元。可以随时停止翻牌,在最优策略下平均能得到多少钱。 输出答案时,小数点后第六位后的全部去掉,不要四舍五入.

Input

一行输入两个数R,B,其值在0到5000之间

Output

在最优策略下平均能得到多少钱。

Sample Input

5 1

Sample Output

4.166666

分析

题目的意思大概就是给一堆牌,有“+1”有“-1”,确定一种拿法(从上往下拿k张之后停止),对于所有这副牌的排列顺序,使最终这些得分的平均値最大,求出这个最大的平均値。(其实就是求最大的期望值)

创建一个数组
E[i][j]
代表有
i
个红牌(+1)和
j
个黑牌(-1)时所能得到的最大期望值。

所以对于
E[i][j]
,我们可以由
E[i-1][j]
E[i][j-1]
推出,相当于是翻一张红牌或翻一张黑牌到达当前状态。乘一下相应的概率就行了。

那么就有

E(i,j)=ii+j∗(E(i−1,j)+1)+ji+j∗(E(i,j−1)−1)

注意,当
E[i][j]
求得小于零时,你当然是希望更大,于是你会将它赋值为0(可以想象宁可保证为0也不想要有可能为负数)

其实,除了这样倒着推,也可以顺着推,可以自己想一想,下面程序也有(其实差不多)

程序

由后面得出当前(倒着推)(被动)

#include <cstdio>
double E[5010][5010];
int R,B;

int main(){
scanf("%d%d",&R,&B);
for (int i=0; i<=R; i++)
for (int j=0; j<=B; j++){
if (i>0) E[i][j]+=(double)i/(double)(i+j)*(E[i-1][j]+1);
if (j>0) E[i][j]+=(double)j/(double)(i+j)*(E[i][j-1]-1);
if (E[i][j]<0) E[i][j]=0;
}
printf("%.6f",E[R]-0.0000005);
}


由当前更新后面(顺着推)(主动)

#include<cstdio>
int R,B;
double E[5010][5010];

int main(){
scanf("%d%d",&R,&B);
for (int i=0; i<=R; i++){
for (int j=0; j<=B; j++){
if (E[i][j]<0) E[i][j]=0;
E[i+1][j]+=(double)(i+1)/(double)(i+j+1)*(E[i][j]+1);
E[i][j+1]+=(double)(j+1)/(double)(i+j+1)*(E[i][j]-1);
}
}
printf("%.6f",E[R][B]-0.0000005);
}


注意

题目中要求的是第六位之后的数直接去掉,不要求四舍五入,可以用到
ans-0.0000005
这一小技巧。

记住一点:

[b]和的期望等于期望的和
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: