bzoj1419--Red is Good--期望dp
问题描述
桌面上有 R 张红牌和 B 张黑牌,随机打乱顺序后放在桌面上,开始一张一张地翻牌,翻到红牌得到 1 美元,黑牌则付出 1 美元。可以随时停止翻牌,在最优策略下平均能得到多少钱。
输入格式
一行输入两个数 R、B。
输出格式
在最优策略下平均能得到多少钱。
样例输入
5 1
样例输出
4.166666
数据规模和约定
R,B<=5000
输出答案时,小数点后第六位后的全部去掉,不要四舍五入。
题解:
今天的考题,顺便贴一波题解……我们定义f(i,j)为当前状态下,还有i张红牌和j张黑牌没翻的期望受益,转移时两种情况下的结果都要考虑。
于是f[i][j]=max(0,i/(i+j)*(f[i-1][j]+1)+j/(i+j)*(f[i][j-1]-1))
空间注意要用滚动数组。
1 #include<iostream> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #define ans1 ((f[j-1][end]+1)*j/i) 7 #define ans2 ((f[j][end]-1)*(i-j)/i) 8 #define ll long long 9 using namespace std; 10 //const int maxn=5001; 11 inline void Edwina() 12 { 13 freopen("red.in","r",stdin); 14 freopen("red.out","w",stdout); 15 } 16 double f[10009][2];//开滚动数组 17 double mmax(double a,double b){return a>b?a:b;} 18 int main() 19 { 20 Edwina(); 21 int R,B,k=0,end=1; 22 scanf("%d%d",&R,&B); 23 for(int i=1;i<=R+B;i++,end^=1,k^=1) 24 { 25 for(int j=0;j<=i&&j<=R;j++) 26 { 27 if(j==0) 28 f[j][k]=0; 29 else 30 { 31 if(i==j) 32 f[j][k]=j; 33 else 34 f[j][k]=mmax(0,ans1+ans2); 35 //ans1 ((f[j-1][end]+1)*j/i) 36 //ans2 ((f[j][end]-1)*(i-j)/i) 37 } 38 } 39 } 40 printf("%.6lf\n",floor(f[R][end]*1000000)/1000000);//对于小数位的处理 41 //ll ans=(ll)(f[R][end]*1000000); 42 //printf("%lld.%06lld\n",ans/1000000,ans%1000000); 43 fclose(stdin); 44 fclose(stdout); 45 return 0; 46 }