AcWing 218 数学期望 + DP

159 篇文章 1 订阅
该博客介绍了一种使用动态规划解决AcWing218题目——扑克牌翻开问题的方法。通过从终止状态开始,以起始状态为目标进行状态转移,计算达到特定条件时还需翻开牌的期望数量。在记忆化搜索过程中,博主分析了不同花色的贡献,并考虑了大小王的处理。最终,通过递归函数实现求解,输出合法状态的期望翻牌数,若无解则返回正无穷。
摘要由CSDN通过智能技术生成
题意

传送门 AcWing 218 扑克牌

题解

满足条件的终止状态较多,而起始状态唯一。考虑以终止状态为初值,起始状态为目标,进行动态规划。 d p [ a ] [ b ] [ c ] [ d ] [ x ] [ y ] dp[a][b][c][d][x][y] dp[a][b][c][d][x][y] 代表初始条件为当前已翻开状态下,还需哟翻开牌的期望数。前 4 4 4 个状态为已翻开的各类牌的数量,后 2 2 2 个状态分别代表大、小王的状态( 0 0 0 为未翻开, 1 1 1 代表已翻开且当做黑桃,以此类推)。设 r s t rst rst 为剩余牌的数量。

a < 13 a<13 a<13,则当前抽到黑桃的贡献为 13 − a r s t × d p [ a + 1 ] [ b ] [ c ] [ d ] [ x ] [ y ] \frac{13-a}{rst}\times dp[a+1][b][c][d][x][y] rst13a×dp[a+1][b][c][d][x][y] 其余花色同理。若小王未抽取,取可转移状态期望最小的一个进行状态转移,其贡献为 1 r s t × min ⁡ 1 ≤ i ≤ 4 d p [ a ] [ b ] [ c ] [ d ] [ i ] [ y ] \frac{1}{rst}\times\min\limits_{1\leq i\leq 4}dp[a][b][c][d][i][y] rst1×1i4mindp[a][b][c][d][i][y]

记忆化搜索求解,若无牌可抽仍未到达 a > = A & b > = B & c > = C & d > = D a >= A \& b >= B \&c >= C \& d >= D a>=A&b>=B&c>=C&d>=D 的终止状态,则期望为正无穷,代表不合法的状态。

#include <bits/stdc++.h>
using namespace std;
const double inf = 1e9;
double dp[14][14][14][14][5][5];
bool vs[14][14][14][14][5][5];
int A, B, C, D;

inline void add(int &a, int &b, int &c, int &d, int x)
{
    if (x == 1)
        ++a;
    else if (x == 2)
        ++b;
    else if (x == 3)
        ++c;
    else if (x == 4)
        ++d;
}

double rec(int a, int b, int c, int d, int x, int y)
{
    double &res = dp[a][b][c][d][x][y];
    if (vs[a][b][c][d][x][y])
        return res;
    vs[a][b][c][d][x][y] = 1;
    res = 0;
    int ta = a, tb = b, tc = c, td = d;
    add(ta, tb, tc, td, x), add(ta, tb, tc, td, y);
    if (ta >= A && tb >= B && tc >= C && td >= D)
        return 0;
    int rst = 54 - ta - tb - tc - td;
    if (!rst)
        return inf;
    if (a < 13)
        res += rec(a + 1, b, c, d, x, y) * (13 - a) / rst;
    if (b < 13)
        res += rec(a, b + 1, c, d, x, y) * (13 - b) / rst;
    if (c < 13)
        res += rec(a, b, c + 1, d, x, y) * (13 - c) / rst;
    if (d < 13)
        res += rec(a, b, c, d + 1, x, y) * (13 - d) / rst;
    if (!x)
        res += min(min(rec(a, b, c, d, 1, y), rec(a, b, c, d, 2, y)), min(rec(a, b, c, d, 3, y), rec(a, b, c, d, 4, y))) / rst;
    if (!y)
        res += min(min(rec(a, b, c, d, x, 1), rec(a, b, c, d, x, 2)), min(rec(a, b, c, d, x, 3), rec(a, b, c, d, x, 4))) / rst;
    return ++res;
}

int main()
{
    scanf("%d%d%d%d", &A, &B, &C, &D);
    double res = rec(0, 0, 0, 0, 0, 0);
    if (res > 54)
        puts("-1.000");
    else
        printf("%.3f\n", res);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值