zoukankan      html  css  js  c++  java
  • 扑克牌 题解

    扑克牌 题解

    题意

    $ $ 有一副扑克牌共 (54) 张,包括黑桃、红桃、梅花和方块四种花色各 (13) 张与 (2) 张大小王。将这副牌反面朝上放置,每次翻一张牌,若翻到大小王可以将其视作任何花色。求最后翻出 (A) 张黑桃、(B) 张红桃、(C) 张梅花和 (D) 张方块的最小期望翻牌次数是多少。


    题解

    (~~~~) 计黑桃为第一种花色,红桃为第二种花色,梅花为第三种花色,方块为第四种花色。

    (~~~~) 一道定义为入门期望DP的题,虽然我当时想了挺久。

    (~~~~) 显然DP至少会定义四个维度表示四种花色拥有的张数。考虑如何处理大小王。

    (~~~~) 因此定义 (dp_{a,b,c,d,x,y}) ,表示翻开 (a) 张黑桃、(b) 张红桃、(c) 张梅花、(d) 张方块,且小王用作第 (x) 种花色,大王用作第 (y) 种花色后凑到要求的种类的期望翻牌最小张数。当 (x=0) 时表示未翻开小王, (y=0) 时表示为翻开大王。

    (~~~~) 考虑一个已知的 (dp_{a,b,c,d,x,y}) 能扩展出哪些状态。

    (~~~~) 以黑桃为例,当你有 (a) 张黑桃,已经翻开 (k) 张牌时,有 (dfrac{13-a}{54-k}) 的概率再翻出一张黑桃。

    (~~~~) 今天学到了一个结论,当某事件发生的概率为 (p) 时,则其期望在 (dfrac{1}{p}) 次实验后第一次出现该事件。具体可以看 知乎上一个回答 (蒟蒻的我只会用结论)。所以就会在期望 (dfrac{54-k}{13-a}) 次翻牌后第一次翻到一张黑桃。所以当你再翻出来一张黑桃时,状态就变成了 (dp_{a+1,b,c,d,x,y}) 。由期望的性质 (operatorname{E(XY)=E(X) imes E(Y)}) 可以得到 (dp_{a+1,b,c,d,x,y}) 一定有贡献来自 (dp_{a,b,c,d,x,y} imes dfrac{54-k}{13-a}) .另外三种花色也是同理。

    (~~~~) 再来考虑双王的问题,若一个状态 (dp_{a,b,c,d,0,y}) ,此时小王未被翻出来,因此已经翻开 (k) 张牌时,有 (dfrac{1}{54-k}) 的概率翻出小王。我们按照上面的方式化简,得到 (dp_{a,b,c,d,x,y}) 也有来自 (dp_{a,b,c,d,0,y} imes (54-k)) 的贡献,其中 (xin[1,4])

    (~~~~) 再来考虑初始状态,可以发现当四种花色及双王满足条件时,其 (dp) 值为 (0) ,而要求的答案就是 (dp_{0,0,0,0,0,0}) ,因此本题是逆推。

    (~~~~) 既然如此,则每个 (dp_{a,b,c,d,x,y}) 一定依托于多翻一张牌的状态。将上面所有式子移项即可。当考虑双王时,可以得到 (dfrac{dp_{a,b,c,d,x,y}}{54-k} (1le xle 4)) 都有可能是 (dp_{a,b,c,d,0,y}) 的一部分加数。因为求最小期望,我们取四个值得最小值即可。

    (~~~~) 综上,本题的DP转移方程是 :

    [Large dp_{a,b,c,d,x,y}= dp_{a+1,b,c,d,x,y} imes dfrac{13-a}{54-sum} +dp_{a,b+1,c,d,x,y} imes dfrac{13-b}{54-sum} +dp_{a,b,c+1,d,x,y} imes dfrac{13-c}{54-sum} +dp_{a,b,c,d+1,x,y} imes dfrac{13-d}{54-sum} +min^{4}_{x=1}{ dfrac{dp_{a,b,c,d,x,y}}{54-sum}} imes[x=0] +min^{4}_{y=1}{ dfrac{dp_{a,b,c,d,x,y}}{54-sum}} imes[y=0] +1 ]

    (~~~~) 当然,每次转移前要先判断 (a+1),(b+1) 等的值是否合法。

    (~~~~) 实现的话记忆化搜索比打递推要方便一些,这里就打的记忆化搜索。


    代码

    #include <cstdio>
    #include <algorithm>
    #define f0 dp[a][b][c][d][x][y]
    #define f1 dfs(a+1,b,c,d,x,y)
    #define f2 dfs(a,b+1,c,d,x,y)
    #define f3 dfs(a,b,c+1,d,x,y)
    #define f4 dfs(a,b,c,d+1,x,y)
    using namespace std;
    double dp[15][15][15][15][5][5];
    int A,B,C,D;
    inline bool check(int a,int b,int c,int d,int x,int 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 true;
    	else return false;
    }
    double dfs(int a,int b,int c,int d,int x,int y)
    {
    	if(f0) return f0;
    	if(check(a,b,c,d,x,y)) return 0;
    	int sum=a+b+c+d+(x!=0)+(y!=0);
    	double cnt=1;
    	if(a<13) cnt+=f1*(13-a)/(54-sum);
    	if(b<13) cnt+=f2*(13-b)/(54-sum);
    	if(c<13) cnt+=f3*(13-c)/(54-sum);
    	if(d<13) cnt+=f4*(13-d)/(54-sum);
    	if(x==0) 
    	{
    		double tmp=1000;
    		for(int i=1;i<=4;i++) tmp=min(tmp,dfs(a,b,c,d,i,y)/(54-sum));
    		cnt+=tmp;
    	}
    	if(y==0)
    	{
    		double tmp=1000;
    		for(int i=1;i<=4;i++) tmp=min(tmp,dfs(a,b,c,d,x,i)/(54-sum));
    		cnt+=tmp;
    	}
    	return dp[a][b][c][d][x][y]=cnt;
    }
    int main() {
    	scanf("%d %d %d %d",&A,&B,&C,&D);
    	if(max(0,A-13)+max(0,B-13)+max(0,C-13)+max(0,D-13)>2)
    	{
    		printf("-1.000");
    		return 0;
    	}
    	double ans=dfs(0,0,0,0,0,0);
    	printf("%.3lf",ans);
    	return 0;
    }
    
  • 相关阅读:
    sqlplus登录用户hang住
    ORACLE_19c用户密码登录失败的问题以及ORA-28040
    索引瘦身_oracle_11g
    Linux内存大页设置
    C++ 总体内容(2)
    C++ 总体内容(1)
    vector中erase的用法
    NGUI中的Tween的委托使用
    IOS Android支持中文与本地文件的读取写入
    Unity人工智能学习—确定性AI算法之追踪算法二
  • 原文地址:https://www.cnblogs.com/Azazel/p/13498697.html
Copyright © 2011-2022 走看看