Expected Cards LightOJ

来源:互联网 发布:进销存软件排名 编辑:程序博客网 时间:2024/05/21 07:59

Taha has got a standard deck of cards with him. In addition to the 52 regular ones, there are 2 joker cards. Every regular card has a rank and a suit. The ranks in ascending order are: A, 2, 3, 4, 5, 6, 7, 8, 9, T, J, Q and K. The suit of a card can be clubs, diamonds, hearts or spades. That means there are 13 clubs, 13 diamonds, 13 hearts and 13 spades - which adds up to 52. The joker cards have no ranks or suits.

One day, Sara gave Taha a challenge. First she randomly shuffles the 54 cards and starts placing one card after another, face-up, on a table. What is the expected number of cards Sara has to place so that there are at least C clubs, D diamonds, H hearts and S spades on the table? Whenever a joker card is encountered, Taha has to assign it to some suit so that the expected number of cards to reach the goal is minimized. The decision of assigning the joker card to some suit has to be made instantly (i.e. before Sara puts the next card on the table). Note that the assignments of the two joker cards don’t necessarily need to be the same.

Input
Input starts with an integer T (≤ 10), denoting the number of test cases.

Each case starts with a line containing four integers in the order C, D, H and S. Each of these integers will be in the range [0, 15].

Output
For each case, print the case number first. Then output the expected number of cards Sara needs to place on the table to achieve the goal. If it’s impossible to reach the goal, irrespective of what assignments Sara opts for, output ‘-1’ (without the quotes) instead. Errors less than 10-6 will be ignored.

Sample Input
4
0 0 0 0
15 13 13 13
1 2 3 4
15 15 15 15
Sample Output
Case 1: 0
Case 2: 54
Case 3: 16.3928186102
Case 4: -1

大致题意:一副标准的扑克牌,有四种不同花色,每个花色有13张牌,还有两张大小王,一共54张牌,随机打乱后,背面朝上放置在桌上,然后你一张一张的去翻,如果翻到大小王,你需要马上让大小王变成四种花色中的一种,给你a,b,c,d四个整数对应所需要翻出的四种花色的最少牌数,问最小期望是多少次。

思路:假设dp[a][b][c][d][e][f] 表示此时已经翻出的前面四种花色的牌数对应分别为a,b,c,d以及大小王所变对应的花色e,f时到达目标状态还需翻牌的期望次数。dp[0][0][0][0][0][0]即答案,然后记忆化搜索一下即可。

代码如下

#include<iostream>#include<cstdio>#include<queue>#include<cmath>#include<cstring>using namespace std;#define LL long long #define ULL unsigned long long const double eps=1e-7;double min(double a,double b){    if(a-b>eps) return b;    else return a;}double dp[15][15][15][15][5][5];int cnt[5];//对应4种花色的牌的数量int A,B,C,D;double dfs(int a,int b,int c,int d,int e,int f){    if(a>13||b>13||c>13||d>13) return 0;    cnt[1]=a;    cnt[2]=b;    cnt[3]=c;    cnt[4]=d;    if(e) cnt[e]++;//如果大小王已经选择过了     if(f) cnt[f]++;    if(cnt[1]>=A&&cnt[2]>=B&&cnt[3]>=C&&cnt[4]>=D) return dp[a][b][c][d][e][f]=0;//如果此时已经满足条件     if(dp[a][b][c][d][e][f]>-1) return dp[a][b][c][d][e][f];//如果此时情况前面已经计算过     double ans=0;    int num=54-cnt[1]-cnt[2]-cnt[3]-cnt[4];//剩余的牌数     if(num==0) return 0;    if(e==0)//如果之前没翻到小王,现在翻到小王     {        double tmp=60;        for(int i=1;i<=4;i++)//选择小王所变花色,使得期望值最小        tmp=min(tmp,dfs(a,b,c,d,i,f));        ans+=tmp/num;    }    if(f==0)//如果之前没翻到大王,现在翻到大王,然后同上     {        double tmp=60;        for(int i=1;i<=4;i++)        tmp=min(tmp,dfs(a,b,c,d,e,i));        ans+=tmp/num;    }    ans+=dfs(a+1,b,c,d,e,f)*(13-a)/num;//翻到花色a     ans+=dfs(a,b+1,c,d,e,f)*(13-b)/num;//翻到花色b     ans+=dfs(a,b,c+1,d,e,f)*(13-c)/num;//翻到花色c     ans+=dfs(a,b,c,d+1,e,f)*(13-d)/num;//翻到花色d    return dp[a][b][c][d][e][f]=ans+1;} void init(){    for(int a=0;a<=13;a++)    for(int b=0;b<=13;b++)    for(int c=0;c<=13;c++)    for(int d=0;d<=13;d++)    for(int e=0;e<=4;e++)    for(int f=0;f<=4;f++)    dp[a][b][c][d][e][f]=-1;}int main() {    int T;    scanf("%d",&T);    for(int cas=1;cas<=T;cas++)    {        init();        scanf("%d%d%d%d",&A,&B,&C,&D);        int f=0;        if(A-13>0) f+=A-13;        if(B-13>0) f+=B-13;        if(C-13>0) f+=C-13;        if(D-13>0) f+=D-13;        if(f>2)        {            printf("Case %d: -1\n",cas);            continue;        }        dfs(0,0,0,0,0,0);        printf("Case %d: %.7lf\n",cas,dp[0][0][0][0][0][0]);    }    return 0;}
原创粉丝点击