[题目链接] [CH3803] 扑克牌
[题面描述] \(54\)张牌,每次随机摸一张,求得到 A张黑桃 B张红桃 C张梅花 D张方块 的期望步数.特别地,大王和小王可以当做任意一种花色,当然,会选择当前的最优策略.
设\(f[a][b][c][d][p][q]\)代表已选了\(a,b,c,d,\)王的情况为\(p,q\)时到达目标的期望步数.设最终状态步数为\(0\),则\(f[0][0][0][0]\)即为所求.
这是因为初始情况只有一个,而最终情况有很多种.
所以这道题用到 记忆化搜索
算出已经选的牌\(sum\),则有
\(f[a][b][c][d][p][q]=\frac{13-a}{54-sum}f[a+1][b][c][d][p][q]+\frac{13-b}{54-sum}f[a][b+1][c][d][p][q]\)
\(+\frac{13-c}{54-sum}f[a][b][c+1][d][p][q]+\frac{13-d}{54-sum}f[a][b][c][d+1][p][q]\)
\(+min\{\frac{1}{54-sum}f[a][b][c][d][1∼4][q]\}(if \ p==0)\)
\(+min\{\frac{1}{54-sum}f[a][b][c][d][p][1∼4]\}(if\ q==0)\)
注意实现细节
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
register LL x=0,f=1;register char c=getchar();
while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f*x;
}
double f[14][14][14][14][5][5];
int t1,t2,t3,t4;
inline double dp(int a,int b,int c,int d,int p,int q){
if(f[a][b][c][d][p][q]) return f[a][b][c][d][p][q];
register double &ans=f[a][b][c][d][p][q];//double &ans的操作
register int x1=a,x2=b,x3=c,x4=d;
if(p==1)x1++;if(p==2)x2++;if(p==3)x3++;if(p==4)x4++;//王的记录
if(q==1)x1++;if(q==2)x2++;if(q==3)x3++;if(q==4)x4++;
if(x1>=t1&&x2>=t2&&x3>=t3&&x4>=t4) return 0;//已经到达
int sum=54-x1-x2-x3-x4;
if(sum<=0) return ans=INF;//不可能
if(a<13) ans+=dp(a+1,b,c,d,p,q)*(13-a)/sum;//注意要乘上概率
if(b<13) ans+=dp(a,b+1,c,d,p,q)*(13-b)/sum;
if(c<13) ans+=dp(a,b,c+1,d,p,q)*(13-c)/sum;
if(d<13) ans+=dp(a,b,c,d+1,p,q)*(13-d)/sum;
if (!p){
double t=dp(a,b,c,d,1,q);
t=min(t,dp(a,b,c,d,2,q));
t=min(t,dp(a,b,c,d,3,q));
t=min(t,dp(a,b,c,d,4,q));
ans+=t/sum;//用王代替最优解
}
if (!q){
double t=dp(a,b,c,d,p,1);
t=min(t,dp(a,b,c,d,p,2));
t=min(t,dp(a,b,c,d,p,3));
t=min(t,dp(a,b,c,d,p,4));
ans+=t/sum;
}
return ++ans;//需要拿一张牌才能转移到下一步
}
int main(){
t1=read(),t2=read(),t3=read(),t4=read();
double Ans=dp(0,0,0,0,0,0);
if(Ans>=INF) Ans=-1;
printf("%.3lf\n",Ans);
}