Light OJ 1364 Expected Cards (期望dp,好题)

时间:2022-08-11 07:26:54

题目自己看吧,不想赘述。

参考链接:http://www.cnblogs.com/jianglangcaijin/archive/2013/01/02/2842389.html

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
/*
dp[c][d][h][s][x1][x2]: 表示有c张为梅花,d张为方块,h张为红桃,s张为草花,第一张王作为x1,第二张作为x2 的情况下,
距离目标状态的期望数。 */
using namespace std;
const int INF=0x3f3f3f3f;
double dp[][][][][][];
int vis[][][][][][];
int C,D,H,S; double dfs(int c,int d,int h,int s,int x1,int x2){
if(vis[c][d][h][s][x1][x2])
return dp[c][d][h][s][x1][x2];
vis[c][d][h][s][x1][x2]=;
int left=-c-d-h-s; //剩余的牌数
if(!x1)
left++;
if(!x2)
left++;
int cnt[]; //现有花色的牌数
cnt[]=c;cnt[]=d;cnt[]=h;cnt[]=s;
if(x1) cnt[x1]++;
if(x2) cnt[x2]++;
if(cnt[]>=C&&cnt[]>=D&&cnt[]>=H&&cnt[]>=S)
return ;
double ans=;
int num[]; //储存各花色剩余的牌数
num[]=-c;
num[]=-d;
num[]=-h;
num[]=-s; //当前抽中c的概率为num[1]/left,下面类同
if(num[])
ans+=1.0*num[]/left*dfs(c+,d,h,s,x1,x2);
if(num[])
ans+=1.0*num[]/left*dfs(c,d+,h,s,x1,x2);
if(num[])
ans+=1.0*num[]/left*dfs(c,d,h+,s,x1,x2);
if(num[])
ans+=1.0*num[]/left*dfs(c,d,h,s+,x1,x2);
double tmp=INF;
if(!x1){
for(int i=;i<=;i++){
tmp=min(tmp,dfs(c,d,h,s,i,x2));
}
ans+=1.0/left*tmp;
}
tmp=INF;
if(!x2){
for(int i=;i<=;i++){
tmp=min(tmp,dfs(c,d,h,s,x1,i));
}
ans+=1.0/left*tmp;
}
ans++; //加1,即必须抽1张牌
dp[c][d][h][s][x1][x2]=ans;
return ans;
}
int main()
{
int t,cases=;
scanf("%d",&t);
while(t--){
scanf("%d%d%d%d",&C,&D,&H,&S);
int x=;
if(C>)
x+=C-;
if(D>)
x+=D-;
if(H>)
x+=H-;
if(S>)
x+=S-;
if(x>){
printf("Case %d: -1\n",++cases);
continue;
}
memset(vis,,sizeof(vis));
memset(dp,,sizeof(dp));
printf("Case %d: %.7lf\n",++cases,dfs(,,,,,));
}
return ;
}