传送门
【题目分析】
定义数组dp[a][b][c][d][x][y]表示当前已经翻了a张黑桃,b张红桃,c张梅花,d张方块,小王状态为x,大王状态为y的期望值,x,y为0-4的数,分别表示黑桃红桃梅花方块和未翻。
那么现在剩下的牌就是res=(54-a-b-c-d-(x!=4)-(y!=4))
那么我们可以得到dp[a][b][c][d][x][y]的递推式:
如果x=4或y=4,那么此时要讨论1/res的概率选到小王或者大王,因为最后要最优,所以一定是在所有花色中选最小值。枚举花色继续枚举即可。因为概率和一定为1,所以对于每个状态的期望加上一个1即可。
然后再记忆化一下就行了。
【代码~】
#include<bits/stdc++.h>
using namespace std;
const int MAXN=20;
int A,B,C,D;
int vis[MAXN][MAXN][MAXN][MAXN][5][5];
double dp[MAXN][MAXN][MAXN][MAXN][5][5],ans;
double solve(int a,int b,int c,int d,int x,int y){
if(vis[a][b][c][d][x][y])
return dp[a][b][c][d][x][y];
vis[a][b][c][d][x][y]=1;
double ret=0.0;
int na=a+(x==0)+(y==0),nb=b+(x==1)+(y==1),nc=c+(x==2)+(y==2),nd=d+(x==3)+(y==3);
if(na>=A&&nb>=B&&nc>=C&&nd>=D)
return dp[a][b][c][d][x][y]=0;
double res=54.0-a-b-c-d-(x!=4)-(y!=4);
if(res<0)
return 100.0;
if(a<13)
ret+=solve(a+1,b,c,d,x,y)*(1.0*(13-a))/res;
if(b<13)
ret+=solve(a,b+1,c,d,x,y)*(1.0*(13-b))/res;
if(c<13)
ret+=solve(a,b,c+1,d,x,y)*(1.0*(13-c))/res;
if(d<13)
ret+=solve(a,b,c,d+1,x,y)*(1.0*(13-d))/res;
if(x==4){
double s=min(solve(a,b,c,d,0,y),min(solve(a,b,c,d,1,y),min(solve(a,b,c,d,2,y),solve(a,b,c,d,3,y))));
ret+=s/res;
}
if(y==4){
double s=min(solve(a,b,c,d,x,0),min(solve(a,b,c,d,x,1),min(solve(a,b,c,d,x,2),solve(a,b,c,d,x,3))));
ret+=s/res;
}
return dp[a][b][c][d][x][y]=ret+1.0;
}
int main(){
cin>>A>>B>>C>>D;
ans=solve(0,0,0,0,4,4);
if(ans>54)
puts("-1.000");
else
printf("%.3lf",ans);
return 0;
}