UVa 12369 Cards

题目概述

Taha\texttt{Taha}Taha 有一副特殊的扑克牌,包含 525252 张常规牌和 222Joker\texttt{Joker}Joker 牌。常规牌的花色分为 梅花方块红心黑桃 四种,每种花色 131313 张。Joker\texttt{Joker}Joker 牌没有花色。Sara\texttt{Sara}Sara 随机洗牌后逐张发牌,目标是使得桌面上至少有 CCC 张梅花、DDD 张方块、HHH 张红心、SSS 张黑桃。当出现 Joker\texttt{Joker}Joker 时,Taha\texttt{Taha}Taha 必须立即将其指定为某种花色,以最小化达成目标所需牌数的期望值。两个 Joker\texttt{Joker}Joker 的指定可以不同。求这个最小期望值,若不可能达成目标则输出 −1.000-1.0001.000

输入格式

  • 第一行:测试用例数 TTTT<50T < 50T<50)。
  • 每行四个整数 C,D,H,SC, D, H, SC,D,H,S0≤C,D,H,S≤150 \le C, D, H, S \le 150C,D,H,S15)。

输出格式

  • 每个测试用例输出一行:Case i: X.XXX,其中 X.XXXX.XXXX.XXX 为期望值,保留三位小数。

解题思路详解

1. 问题分析

这是一个带有控制的随机过程问题,可以看作一个马尔可夫决策过程(MDP\texttt{MDP}MDP

  • 状态:已经抽到的四种花色的数量,以及已经使用且分配到各花色的 Joker\texttt{Joker}Joker 数量。
  • 动作:当抽到 Joker\texttt{Joker}Joker 时,选择将其分配给哪种花色。
  • 目标:最小化达到目标所需的期望抽牌数。

2. 状态定义

(c,d,h,s)(c, d, h, s)(c,d,h,s) 表示已经抽到的四种花色的实际牌数(不包括 Joker\texttt{Joker}Joker 转换来的)。
(jc,jd,jh,js)(j_c, j_d, j_h, j_s)(jc,jd,jh,js) 表示 Joker\texttt{Joker}Joker 被指定为四种花色的数量。
由于只有 222 张 Joker,有 0≤jc+jd+jh+js≤20 \le j_c + j_d + j_h + j_s \le 20jc+jd+jh+js2

当前有效牌数为:

  • 梅花:c+jcc + j_cc+jc
  • 方块:d+jdd + j_dd+jd
  • 红心:h+jhh + j_hh+jh
  • 黑桃:s+jss + j_ss+js

终止条件
c+jc≥C,d+jd≥D,h+jh≥H,s+js≥S c + j_c \ge C,\quad d + j_d \ge D,\quad h + j_h \ge H,\quad s + j_s \ge S c+jcC,d+jdD,h+jhH,s+jsS

3. 状态转移与期望计算

E(c,d,h,s,jc,jd,jh,js)E(c, d, h, s, j_c, j_d, j_h, j_s)E(c,d,h,s,jc,jd,jh,js) 为当前状态下的最小期望抽牌数(从当前开始到结束)。
当前已抽牌数:
drawn=c+d+h+s+jc+jd+jh+js \texttt{drawn} = c + d + h + s + j_c + j_d + j_h + j_s drawn=c+d+h+s+jc+jd+jh+js
剩余牌数:
remain=54−drawn \texttt{remain} = 54 - \texttt{drawn} remain=54drawn

remain=0\texttt{remain} = 0remain=0 且未达标,则 E=∞E = \inftyE=(不可达)。

对于下一张牌,可能是:

  • 梅花:概率 pc=13−cremainp_c = \frac{13 - c}{\text{remain}}pc=remain13c,期望贡献 pc×(1+E(c+1,d,h,s,jc,jd,jh,js))p_c \times (1 + E(c+1, d, h, s, j_c, j_d, j_h, j_s))pc×(1+E(c+1,d,h,s,jc,jd,jh,js))
  • 方块:概率 pd=13−dremainp_d = \frac{13 - d}{\text{remain}}pd=remain13d,期望贡献 pd×(1+E(c,d+1,h,s,jc,jd,jh,js))p_d \times (1 + E(c, d+1, h, s, j_c, j_d, j_h, j_s))pd×(1+E(c,d+1,h,s,jc,jd,jh,js))
  • 红心:概率 ph=13−hremainp_h = \frac{13 - h}{\text{remain}}ph=remain13h,期望贡献 ph×(1+E(c,d,h+1,s,jc,jd,jh,js))p_h \times (1 + E(c, d, h+1, s, j_c, j_d, j_h, j_s))ph×(1+E(c,d,h+1,s,jc,jd,jh,js))
  • 黑桃:概率 ps=13−sremainp_s = \frac{13 - s}{\text{remain}}ps=remain13s,期望贡献 ps×(1+E(c,d,h,s+1,jc,jd,jh,js))p_s \times (1 + E(c, d, h, s+1, j_c, j_d, j_h, j_s))ps×(1+E(c,d,h,s+1,jc,jd,jh,js))
  • Joker\texttt{Joker}Joker:概率 pj=2−(jc+jd+jh+js)remainp_j = \frac{2 - (j_c + j_d + j_h + j_s)}{\text{remain}}pj=remain2(jc+jd+jh+js),此时需要选择一种花色使得后续期望最小:
    min⁡{1+E(c,d,h,s,jc+1,jd,jh,js)1+E(c,d,h,s,jc,jd+1,jh,js)1+E(c,d,h,s,jc,jd,jh+1,js)1+E(c,d,h,s,jc,jd,jh,js+1) \min \begin{cases} 1 + E(c, d, h, s, j_c+1, j_d, j_h, j_s) \\ 1 + E(c, d, h, s, j_c, j_d+1, j_h, j_s) \\ 1 + E(c, d, h, s, j_c, j_d, j_h+1, j_s) \\ 1 + E(c, d, h, s, j_c, j_d, j_h, j_s+1) \end{cases} min1+E(c,d,h,s,jc+1,jd,jh,js)1+E(c,d,h,s,jc,jd+1,jh,js)1+E(c,d,h,s,jc,jd,jh+1,js)1+E(c,d,h,s,jc,jd,jh,js+1)

总期望:
E=∑suitpsuit×(1+Enext)+pj×Ejoker-best E = \sum_{\texttt{suit}} p_{\texttt{suit}} \times (1 + E_{\texttt{next}}) + p_j \times E_{\texttt{joker-best}} E=suitpsuit×(1+Enext)+pj×Ejoker-best

4. 可行性判断

由于每种花色最多 131313 张牌,若目标超过 131313,则超出的部分必须由 Joker\texttt{Joker}Joker 补充。
设:
needExtra=max⁡(0,C−13)+max⁡(0,D−13)+max⁡(0,H−13)+max⁡(0,S−13) \texttt{needExtra} = \max(0, C-13) + \max(0, D-13) + \max(0, H-13) + \max(0, S-13) needExtra=max(0,C13)+max(0,D13)+max(0,H13)+max(0,S13)
needExtra>2\texttt{needExtra} > 2needExtra>2,则即使全部 Joker\texttt{Joker}Joker 都用上也不够,输出 −1.000-1.0001.000

5. 算法设计

使用记忆化搜索(Memoization\texttt{Memoization}Memoization 实现动态规划:

  • 状态维数:14×14×14×14×3×3×3×3≈3.8×10614 \times 14 \times 14 \times 14 \times 3 \times 3 \times 3 \times 3 \approx 3.8 \times 10^614×14×14×14×3×3×3×33.8×106,可以存储。
  • 递归边界:达标时返回 000,无牌可抽时返回 ∞\infty
  • 利用概率计算期望,对 Joker\texttt{Joker}Joker 决策取最小值。

6. 复杂度分析

  • 状态数:144×34≈3.8×10614^4 \times 3^4 \approx 3.8 \times 10^6144×343.8×106
  • 每个状态转移:常数时间(最多 888 种可能)
  • 总时间复杂度:O(状态数×8)O(\text{状态数} \times 8)O(状态数×8),在可接受范围内。

代码实现

// Cards
// UVa ID: 12369
// Verdict: Accepted
// Submission Date: 2025-12-15
// UVa Run Time: 1.010s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>
using namespace std;

const double INF = 1e30; // 表示无穷大,用于不可达状态
const int MAXN = 14;
double memo[MAXN][MAXN][MAXN][MAXN][3][3][3][3];
bool visited[MAXN][MAXN][MAXN][MAXN][3][3][3][3];
int needC, needD, needH, needS;

double dfs(int c, int d, int h, int s, int jc, int jd, int jh, int js) {
    // jc, jd, jh, js 分别表示Joker被指定为梅花、方块、红心、黑桃的数量
    // 总Joker使用数 = jc + jd + jh + js ≤ 2
    
    int totalC = c + jc;
    int totalD = d + jd;
    int totalH = h + jh;
    int totalS = s + js;
    
    if (totalC >= needC && totalD >= needD && totalH >= needH && totalS >= needS) {
        return 0.0; // 目标已达成,无需再抽牌
    }
    
    // 边界检查
    if (c > 13 || d > 13 || h > 13 || s > 13) return INF;
    if (jc + jd + jh + js > 2) return INF;
    if (c + d + h + s + jc + jd + jh + js > 54) return INF;
    
    int stateC = min(c, 13);
    int stateD = min(d, 13);
    int stateH = min(h, 13);
    int stateS = min(s, 13);
    
    if (visited[stateC][stateD][stateH][stateS][jc][jd][jh][js]) {
        return memo[stateC][stateD][stateH][stateS][jc][jd][jh][js];
    }
    
    int remainingClubs = 13 - c;
    int remainingDiamonds = 13 - d;
    int remainingHearts = 13 - h;
    int remainingSpades = 13 - s;
    int remainingJokers = 2 - (jc + jd + jh + js);
    int drawnCards = c + d + h + s + jc + jd + jh + js;
    int remainingCards = 54 - drawnCards;
    
    if (remainingCards == 0) {
        // 无牌可抽仍未达标
        visited[stateC][stateD][stateH][stateS][jc][jd][jh][js] = true;
        memo[stateC][stateD][stateH][stateS][jc][jd][jh][js] = INF;
        return INF;
    }
    
    double expected = 0.0;
    
    // 抽到梅花的期望
    if (remainingClubs > 0) {
        double prob = (double)remainingClubs / remainingCards;
        expected += prob * (1.0 + dfs(c + 1, d, h, s, jc, jd, jh, js));
    }
    
    // 抽到方块的期望
    if (remainingDiamonds > 0) {
        double prob = (double)remainingDiamonds / remainingCards;
        expected += prob * (1.0 + dfs(c, d + 1, h, s, jc, jd, jh, js));
    }
    
    // 抽到红心的期望
    if (remainingHearts > 0) {
        double prob = (double)remainingHearts / remainingCards;
        expected += prob * (1.0 + dfs(c, d, h + 1, s, jc, jd, jh, js));
    }
    
    // 抽到黑桃的期望
    if (remainingSpades > 0) {
        double prob = (double)remainingSpades / remainingCards;
        expected += prob * (1.0 + dfs(c, d, h, s + 1, jc, jd, jh, js));
    }
    
    // 抽到Joker的期望
    if (remainingJokers > 0) {
        double prob = (double)remainingJokers / remainingCards;
        double best = INF;
        
        // 尝试四种花色,选择期望最小的
        if (jc + jd + jh + js < 2) {
            best = min(best, 1.0 + dfs(c, d, h, s, jc + 1, jd, jh, js));
            best = min(best, 1.0 + dfs(c, d, h, s, jc, jd + 1, jh, js));
            best = min(best, 1.0 + dfs(c, d, h, s, jc, jd, jh + 1, js));
            best = min(best, 1.0 + dfs(c, d, h, s, jc, jd, jh, js + 1));
        }
        
        expected += prob * best;
    }
    
    visited[stateC][stateD][stateH][stateS][jc][jd][jh][js] = true;
    memo[stateC][stateD][stateH][stateS][jc][jd][jh][js] = expected;
    return expected;
}

int main() {
    int T;
    cin >> T;
    for (int t = 1; t <= T; t++) {
        cin >> needC >> needD >> needH >> needS;
        
        // 检查是否可能
        int required = 0;
        if (needC > 13) required += needC - 13;
        if (needD > 13) required += needD - 13;
        if (needH > 13) required += needH - 13;
        if (needS > 13) required += needS - 13;
        
        if (required > 2) {
            printf("Case %d: -1.000\n", t);
            continue;
        }
        
        // 初始化记忆化数组
        memset(visited, 0, sizeof(visited));
        double result = dfs(0, 0, 0, 0, 0, 0, 0, 0);
        
        if (result > 1e20) {
            printf("Case %d: -1.000\n", t);
        } else {
            printf("Case %d: %.3lf\n", t, result);
        }
    }
    return 0;
}

总结

本题的核心在于状态的定义期望的计算

  • 状态需要区分“抽到的花色牌”和“Joker\texttt{Joker}Joker 转换的花色牌”,因为 Joker\texttt{Joker}Joker 的分配是可控决策。
  • 期望计算采用标准的条件期望公式,对 Joker\texttt{Joker}Joker 的决策取最小值。
  • 使用记忆化搜索避免重复计算,确保在合理时间内完成。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值