概率dp经典题目
f[a][b][c][d][x][y],黑桃a张,红桃b张,梅花c张,方块d张。大王小王状态x,y(等于0代表每抽到,等于1,2,3,4代表摸到四种花色)时,摸到满足题意的状态的期望张数。
下一张摸牌有6种情况:四种花色,大小王。dfs枚举递推即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
//#define a(i,j) a[(i)*(m+2)+(j)] //m是矩阵的列数
//pop_back()
const int seed=131;
const int M = 16;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
*/
int A,B,C,D;
double f[M][M][M][M][5][5];
double dfs(int a,int b,int c,int d,int x,int y)
{
if(f[a][b][c][d][x][y]>1e-8)return f[a][b][c][d][x][y];
if(a+(x==1)+(y==1)>=A&&b+(x==2)+(y==2)>=B&&c+(x==3)+(y==3)>=C&&d+(x==4)+(y==4)>=D)return 0; //边界
double ans=1.0;//无论哪种情况都要再翻一张
int sum=a+b+c+d+(x!=0)+(y!=0);
if(a<13)ans+=dfs(a+1,b,c,d,x,y)*(13-a)/(54-sum);//摸到黑桃
if(b<13)ans+=dfs(a,b+1,c,d,x,y)*(13-b)/(54-sum);//摸到红桃
if(c<13)ans+=dfs(a,b,c+1,d,x,y)*(13-c)/(54-sum);//摸到梅花
if(d<13)ans+=dfs(a,b,c,d+1,x,y)*(13-d)/(54-sum);//摸到方块
double xi=1e9,di=1e9;
if(x==0)//大王还在 摸到大王
{
for(int i=1;i<=4;i++)xi=min(xi,dfs(a,b,c,d,i,y)/(54-sum));
ans+=xi;
}
if(y==0)//小王还在 摸到小王
{
for(int i=1;i<=4;i++)di=min(di,dfs(a,b,c,d,x,i)/(54-sum));
ans+=di;
}
return f[a][b][c][d][x][y]=ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>A>>B>>C>>D;
if(max(A-13,0)+max(B-13,0)+max(C-13,0)+max(D-13,0)>2){
cout<<"-1.000"<<endl;
return 0;
}
printf("%.3f\n",dfs(0,0,0,0,0,0));
return 0;
}