218. 扑克牌 - 记忆化概率dp

Admin 生日那天,Rainbow 来找 Admin 玩扑克牌。

玩着玩着 Rainbow 觉得太没意思了,于是决定给 Admin 一个考验。

Rainbow 把一副扑克牌(54 张)随机洗开,倒扣着放成一摞。

然后 Admin 从上往下依次翻开每张牌,每翻开一张黑桃、红桃、梅花或者方块,就把它放到对应花色的堆里去。

Rainbow 想问问 Admin,得到 A 张黑桃、B 张红桃、C 张梅花、D 张方块需要翻开的牌的张数的期望值 E 是多少?

特殊地,如果翻开的牌是大王或者小王,Admin 将会把它作为某种花色的牌放入对应堆中,使得放入之后 E 的值尽可能小。

由于 Admin 和 Rainbow 还在玩扑克,所以这个程序就交给你来写了。

输入格式

输入仅由一行,包含四个用空格隔开的整数,A,B,C,D。

输出格式

输出需要翻开的牌数的期望值 E,四舍五入保留 3 位小数。

如果不可能达到输入的状态,输出 -1.000

数据范围

0≤A,B,C,D≤15

输入样例:

复制代码
1 2 3 4

输出样例:

复制代码
16.393
cpp 复制代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

const int N = 15, INF = 1e20;

int A, B, C, D;
double f[N][N][N][N][5][5];

double dp(int a, int b, int c, int d, int x, int y)
{
    //if(a > 13 || b > 13 || c > 13 || d > 13)return INF;
    
	double &v = f[a][b][c][d][x][y];
	if(v >= 0)return v;
	int as = a + (x == 0) + (y == 0);
	int bs = b + (x == 1) + (y == 1);
	int cs = c + (x == 2) + (y == 2);
	int ds = d + (x == 3) + (y == 3);
	if(as >= A && bs >= B && cs >= C && ds >= D)return v = 0;
	
	int sum = a + b + c + d + (x != 4) + (y != 4);
	sum = 54 - sum;
	if(sum == 0)return v = INF;
	
	v = 1;
	if(a < 13)v += (13.0 - a) / sum * dp(a + 1, b, c, d, x, y);
	if(b < 13)v += (13.0 - b) / sum * dp(a, b + 1, c, d, x, y);
	if(c < 13)v += (13.0 - c) / sum * dp(a, b, c + 1, d, x, y);
	if(d < 13)v += (13.0 - d) / sum * dp(a, b, c, d + 1, x, y);
	if(x == 4)
	{
		double t = INF;
		for(int i = 0; i < 4; i ++)
		{
			t = min(t, 1.0 / sum * dp(a, b, c, d, i, y));
		}
		v += t;
	}
	if(y == 4)
	{
		double t = INF;
		for(int i = 0; i < 4; i ++)
		{
			t = min(t, 1.0 / sum * dp(a, b, c, d, x, i));
		}
		v += t;
	}
	return v;
}

int main()
{
	//IOS
	cin >> A >> B >> C >> D;
	
	memset(f, -1, sizeof f);
	double t = dp(0, 0, 0, 0, 4, 4);
	if(t > INF / 2)t = -1;
	
	printf("%.3lf", t);
	
	return 0;
}

思路和绿豆蛙那题有点像,一个点的期望等于所有 下一个点的期望乘以相应概率 之和,和图沾点边。

f[a][b][c][d][x][y]

a、b、c、d分别表示每个花色对应的数量,x表示大王,0~3对应所在花色,4表示在牌堆里

小王同理。

相关推荐
qq_29654465几秒前
最新B站短视频、长视频外,动漫、各类线上课程,付费课程下载
c++
m0_736919103 分钟前
C++中的类型标签分发
开发语言·c++·算法
2301_790300969 分钟前
C++与微服务架构
开发语言·c++·算法
一切尽在,你来13 分钟前
C++多线程教程-1.1.4 并发编程的风险(竞态条件、死锁、数据竞争、资源争用)
开发语言·c++
重生之我是Java开发战士16 分钟前
【优选算法】前缀和:一二维前缀和,寻找数组的中心下标,除自身以外数组的乘积,和为K的子数组,和可被K整除的子数组,连续数组,矩阵区域和
线性代数·算法·矩阵
梵刹古音18 分钟前
【C语言】 循环结构
c语言·开发语言·算法
消失的旧时光-194321 分钟前
C++ 函数参数传递方式总结:什么时候用值传递、引用、const 引用?
开发语言·c++
一匹电信狗23 分钟前
【C++】CPU的局部性原理
开发语言·c++·系统架构·学习笔记·c++11·智能指针·新特性
皮皮哎哟25 分钟前
冒泡排序与数组传递全解析 一维二维指针数组及二级指针应用指南
c语言·算法·冒泡排序·二维数组·指针数组·传参·二级指针
m0_5613596727 分钟前
C++代码冗余消除
开发语言·c++·算法