Red is good题解
Red is good
时间限制: 1 Sec 内存限制: 64 MB题目描述
桌面上有R张红牌和B张黑牌,随机打乱顺序后放在桌面上,开始一张一张地翻牌,翻到红牌得到1美元,黑牌则付出1美元。可以随时停止翻牌,在最优策略下平均能得到多少钱。
输入
一行输入两个数R,B,其值在0到5000之间
输出
在最优策略下平均能得到多少钱。
样例输入
5 1
样例输出
4.166666
提示
输出答案时,小数点后第六位后的全部去掉,不要四舍五入.
solution:
这题一开始想的是正着推,按照取得顺序拿,当红球数量小于黑球数量时跳出,但是那样会少考虑许多本来会出现的情况,于是需要反正来,ans[i][j]表示红球有i个黑球有j个的得分,ans[i][0]=i,ans[0][j]=0(因为此时没有红球了无法得分我们不会接着取),对于ij均不为0的举个例子,ans[2][1]有2/3的概率的一分然后到达状态ans[1][1]也有1/3的概率丢掉1分然后到达状态ans[2][0],所以ans[2][1]=2/3*(ans[1][1]+1)+1/3*(ans[2][0]-1);
所以转移的式子为ans[j][i-j]=(j/i)*(1+ans[j-1][i-j])+((i-j)/i)*(ans[j][i-j-1]-1);
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int r,b,now,state; 8 double ans[2][5001]; 9 double max(double a,double b) { 10 return a>b?a:b; 11 } 12 int main() { 13 scanf("%d%d",&r,&b); 14 ans[0][0]=0; 15 tot=r+b; 16 for(int i=1; i<=tot; ++i) { 17 for(int j=min(i,r); j>=0; --j) { 18 if(i-j>b) { 19 break; 20 } 21 if(i==j) { 22 ans[j][0]=(double)j; 23 continue; 24 } 25 if(!j) { 26 ans[0][j]=(double)0; 27 continue; 28 } 29 ans[j][i-j]=((double)j/(double)i)*(1+ans[j-1][i-j])+((double)(i-j)/(double)i)*(ans[j][i-j-1]-1); 30 } 31 } 32 printf("%0.6lf",ans[r][b]-0.0000005); 33 return 0; 34 }
此时本菜鸡悲催的发现炸内存了,然后开了个滚动数组,上一个转移按照每一层,滚动数组则可以斜着一行行转移。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int r,b,now,state; 8 double ans[2][5001]; 9 double max(double a,double b) { 10 return a>b?a:b; 11 } 12 int main() { 13 scanf("%d%d",&r,&b); 14 for(int i=1; i<=r; ++i) { 15 now=state^1; 16 ans[now][0]=(double)i; 17 for(int j=1; j<=b; ++j) { 18 ans[now][j]=max(0.0,((double)i/(double)(i+j))*(1+ans[state][j])+((double)j/(double)(i+j))*(ans[now][j-1]-1)); 19 } 20 state^=1; 21 } 22 printf("%0.6lf",ans[state][b]-0.0000005); 23 return 0; 24 }