扑克牌
题目大意,即有54张牌(有大王小王),询问,随机从中抽牌不放回,问得到A张黑桃、B张红桃、C张梅花、D张方块所需抽牌的牌数的期望数,注意抽到的大王和小王可以作为任意一种花色的牌对待,但是所作为的方案,要使最终的期望最小,0<=A,B,C,D<=15。
解
显然为期望题,显然顺推记概率太麻烦,考虑倒推,于是设\(f[a][b][c][d][x][y]\)为 已经 抽出a张黑桃,b张红桃,c张梅花,d张方块,大小王状态为x,y
(0表示未抽到,1表示作为黑桃,2红桃,3梅花,4方块) 到达目标状态的数学期望 ,设\(sum=a+b+c+d+(x>0)+(y>0)\),根据递推套路,我们不难有
\[f[a][b][c][d][x][y]=f[a+1][b][c][d][x][y]\times\frac{13-a}{54-sum}+
\]
\[f[a][b+1][c][d][x][y]\times\frac{13-b}{54-sum}+f[a][b][c+1][d][x][y]\times\frac{13-c}{54-sum}+
\]
\[f[a][b][c+1][d][x][y]\times\frac{13-c}{54-sum}+f[a][b][c][d+1][x][y]\times\frac{13-d}{54-sum}+
\]
\[\frac{1}{54-sum}\times min_{i=1,!x}^4(f[a][b][c][d][i][y])
\]
\[\frac{1}{54-sum}\times min_{i=1,!x}^4(f[a][b][c][d][x][i])+1
\]
再根据所需要的牌数作为边界,注意大小王的影响,故边界不简简单单地为\(f[A][B[C][D][?][?]=0\),答案不难得知为\(f[0][0][0][0][0][0]\),根据递推方程转移即可。
参考代码:
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define db double
#define exact 0.001
using namespace std;
int A,B,C,D;
db dp[14][14][14][14][5][5];
il db dfs(int,int,int,int,int,int);
il bool check(int,int,int,int,int,int);
template<class free>il free Min(free,free);
int main(){
int check(0);
scanf("%d%d%d%d",&A,&B,&C,&D);
if(A>13)check+=A-13;if(B>13)check+=B-13;
if(C>13)check+=C-13;if(D>13)check+=D-13;
if(check>2)puts("-1.000");
else printf("%.3lf",dfs(0,0,0,0,0,0));
return 0;
}
template<class free>
il free Min(free a,free b){
return a<b?a:b;
}
il db dfs(int a,int b,int c,int d,int x,int y){
db &ans=dp[a][b][c][d][x][y];
if(ans>exact)return dp[a][b][c][d][x][y];
if(check(a,b,c,d,x,y))return 0;
int rest(54-(a+b+c+d+(x>0)+(y>0)));
if(a<13)ans+=dfs(a+1,b,c,d,x,y)*(13-a)/rest;
if(b<13)ans+=dfs(a,b+1,c,d,x,y)*(13-b)/rest;
if(c<13)ans+=dfs(a,b,c+1,d,x,y)*(13-c)/rest;
if(d<13)ans+=dfs(a,b,c,d+1,x,y)*(13-d)/rest;
if(!x)ans+=Min(Min(dfs(a,b,c,d,1,y),dfs(a,b,c,d,2,y)),
Min(dfs(a,b,c,d,3,y),dfs(a,b,c,d,4,y)))/rest;
if(!y)ans+=Min(Min(dfs(a,b,c,d,x,1),dfs(a,b,c,d,x,2)),
Min(dfs(a,b,c,d,x,3),dfs(a,b,c,d,x,4)))/rest;
return ++ans;
}
il bool check(int a,int b,int c,int d,int x,int y){
if(x==1)++a;else if(x==2)++b;else if(x==3)++c;else if(x==4)++d;
if(y==1)++a;else if(y==2)++b;else if(y==3)++c;else if(y==4)++d;
if(a>=A&&b>=B&&c>=C&&d>=D)return true;else return false;
}