• 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
    1. #include
    2. #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    3. #define endl '\n'
    4. using namespace std;
    5. typedef pair<int, int> PII;
    6. typedef long long ll;
    7. const int N = 15, INF = 1e9;
    8. int A, B, C, D;
    9. double f[N][N][N][N][5][5];
    10. double dp(int a, int b, int c, int d, int x, int y)
    11. {
    12. //if(a > 13 || b > 13 || c > 13 || d > 13)return INF;
    13. double &v = f[a][b][c][d][x][y];
    14. if(v >= 0)return v;
    15. int as = a + (x == 0) + (y == 0);
    16. int bs = b + (x == 1) + (y == 1);
    17. int cs = c + (x == 2) + (y == 2);
    18. int ds = d + (x == 3) + (y == 3);
    19. if(as >= A && bs >= B && cs >= C && ds >= D)return v = 0;
    20. int sum = a + b + c + d + (x != 4) + (y != 4);
    21. sum = 54 - sum;
    22. if(sum == 0)return v = INF;
    23. v = 1;
    24. if(a < 13)v += (13.0 - a) / sum * dp(a + 1, b, c, d, x, y);
    25. if(b < 13)v += (13.0 - b) / sum * dp(a, b + 1, c, d, x, y);
    26. if(c < 13)v += (13.0 - c) / sum * dp(a, b, c + 1, d, x, y);
    27. if(d < 13)v += (13.0 - d) / sum * dp(a, b, c, d + 1, x, y);
    28. if(x == 4)
    29. {
    30. double t = INF;
    31. for(int i = 0; i < 4; i ++)
    32. {
    33. t = min(t, 1.0 / sum * dp(a, b, c, d, i, y));
    34. }
    35. v += t;
    36. }
    37. if(y == 4)
    38. {
    39. double t = INF;
    40. for(int i = 0; i < 4; i ++)
    41. {
    42. t = min(t, 1.0 / sum * dp(a, b, c, d, x, i));
    43. }
    44. v += t;
    45. }
    46. return v;
    47. }
    48. int main()
    49. {
    50. //IOS
    51. cin >> A >> B >> C >> D;
    52. memset(f, -1, sizeof f);
    53. double t = dp(0, 0, 0, 0, 4, 4);
    54. if(t > INF / 2)t = -1;
    55. printf("%.3lf", t);
    56. return 0;
    57. }

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

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

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

    小王同理。

    正常来说应该是从0 0 0 0 4 4这个状态正着推出答案,但由于终点个数过于多了,难以计算,不如反向建边,以0 0 0 0 4 4为终点。

  • 相关阅读:
    post和get
    编译原理:语法分析(自顶向下)
    MAC版Gradle构建Spring5.X源码阅读环境
    【英语】常见连音规则
    K210 调节颜色阈值识别红绿黄三色
    服务器开发25:用libevent充当游戏服务器之间连接(libevent笔记及源码剖析)
    IDM下载器_Internet Download Manager 6.42.7
    微信小程序在线阅读系统微信小程序设计与实现
    MySQL主从数据库搭建
    中国金控盐碱地水稻 国稻种芯-林裕豪:粮食安全两会热点
  • 原文地址:https://blog.csdn.net/a1695574118/article/details/132874326