题意
传送门 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] rst13−a×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×1≤i≤4mindp[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;
}