根据书上的提示这是一道数学期望和动态规划结合的题目
扑克牌是由各种花色各(13)张+带小王组成的,总共由(54)张牌组成
设(f[a][b][c][d][x][y])表示已经拿到了(a)张黑桃,(b)张红桃,(c)张梅花,(d)张方块,小王和大王的状态分别是(x,y)其中(x=0)表示放到黑桃里,(1)表示放到红桃里,(2)表示放到梅花里,(3)表示放到方块里,(4)则表示没有拿到((y)同理)的期望翻开次数
我们可以通过计算轻松获得到当前的翻到的牌的数量:(sum=a+b+c+d+(x==4)+(y==4))
(update):上面写错了,应该是(x!=4和y!=4),淦
剩下的牌的数量是(Sum=54-sum)
现在事情变得通透了起来,淦
以黑桃为例,剩余黑桃的数量为(13-a),那么下一张牌翻到黑桃的概率就是(frac{13-a}{Sum}(Sum eq 0))
那么对答案的贡献就是(frac{13-a}{Sum}*f[a+1][b][c][d][x][y])(反着来递推)
其他的花色类似,这里就不在赘述了
再来看带小王的情况
特殊地,如果翻开的牌是大王或者小王,(Admin)将会把它作为某种花色的牌放入对应堆中,使得放入之后(E)的值尽可能小。
我们还是按照上面花色的分析思路,以小王为例
剩余的小王数量就是(1-(x==4)),剩余的牌的数量仍是(Sum)
显然抽到小王的概率就是(frac{1-(x==4)}{Sum}(Sum eq 0)),貌似只有当(x=4)的情况才有贡献,所有不用考虑其他情况,淦
如果抽到小王,我们把它作为某种花色的牌放入对应堆中,使得放入之后E的值尽可能小。
所以小王的贡献就是(frac{1}{Sum}min_{0 le i le 3}{f[a][b][c][d][i][y]})
大王情况类似,这里就不在赘述了
综上转移方程就是
边界问题:
-
如果已经翻开的牌的数量答案的题目的要求,则期望为(0),例如(a+(x==0)+(y==0))
- 注意这个条件应该是所有翻开的牌都满足,就是说条件使用&&链接的,淦
-
若(54)张牌被翻完但是仍无法到岸,即(54-sumle0),则期望为(infty)
目标:
(f[0][0][0][0][4][4])
#include<bits/stdc++.h>
using namespace std;
const int N=15;
double f[N][N][N][N][5][5];
int v[N][N][N][N][5][5];
int A,B,C,D;
double solve(int a,int b,int c,int d,int x,int y)
{
if(v[a][b][c][d][x][y]) return f[a][b][c][d][x][y];
v[a][b][c][d][x][y]=1;
if(a+(x==0)+(y==0)>=A&&b+(x==1)+(y==1)>=B&&c+(x==2)+(y==2)>=C&&d+(x==3)+(y==3)>=D) return 0;
double sum=1.0;
int cnt=a+b+c+d+(x!=4)+(y!=4);
if(a<13) sum+=solve(a+1,b,c,d,x,y)*(13-a)/(54-cnt);
if(b<13) sum+=solve(a,b+1,c,d,x,y)*(13-b)/(54-cnt);
if(c<13) sum+=solve(a,b,c+1,d,x,y)*(13-c)/(54-cnt);
if(d<13) sum+=solve(a,b,c,d+1,x,y)*(13-d)/(54-cnt);
if(x==4)
{
double minn1=1e9;
for(int i=0;i<=3;++i) minn1=min(minn1,solve(a,b,c,d,i,y)/(54-cnt));
sum+=minn1;
}
if(y==4)
{
double minn2=1e9;
for(int j=0;j<=3;++j) minn2=min(minn2,solve(a,b,c,d,x,j)/(54-cnt));
sum+=minn2;
}
return f[a][b][c][d][x][y]=sum;
}
int main()
{
cin>>A>>B>>C>>D;
if(max(A-13,0)+max(B-13,0)+max(C-13,0)+max(D-13,0)>2){
puts("-1.000");
return 0;
}
double ans=solve(0,0,0,0,4,4);
printf("%.3f",ans);
return 0;
}