首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

HDU 4336 Card Collector:概率 DP + 狀態壓縮求期望收集時間

     編輯:關於C++

問題描述

N 種卡片(N ≤ 20),每包零食隨機含一張卡片,第 i 種概率 p_i,也可能無卡片(∑p_i ≤ 1)。求集齊所有 N 種卡片的期望購買包數。

狀態壓縮 DP 定義

dp[mask] 表示已擁有卡片集合為 mask 時,還需要購買的期望包數。目標求 dp[0]。

轉移:從 mask 買一包,

  • 概率 p0 = 1 - ∑p_i 什麼也沒有,狀態不變,期望增加 1。
  • 概率 p_i 得到卡片 i:
    • 若已有(mask & (1<),狀態不變。
    • 若無,轉移到 mask | (1<。

方程:

dp[mask] = 1 + p0·dp[mask] + Σ_{i∈mask} p_i·dp[mask] + Σ_{i∉mask} p_i·dp[mask|(1<

移項整理:

dp[mask] = (1 + Σ_{i∉mask} p_i·dp[mask|(1<

代碼實現

#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

double p[22], dp[1<<20];
int n;

double solve(int mask) {
    if (mask == (1< 0) return dp[mask];
    
    double sum_p = 0, exp = 1;
    for (int i = 0; i < n; ++i) {
        if (mask & (1<

關鍵點解析

  1. 分母意義:sum_p 是「獲得新卡片」的總概率。若 sum_p == 0(已集齊或剩餘卡片概率為 0),基本情況返回 0。
  2. 遞歸順序:從全集向空集遞歸,或按 mask 從大到小迭代 DP 均可。遞歸 + 記憶化代碼最簡潔。
  3. 精度:double 足夠,輸出 %.3f 或 %.4f 滿足 1e-4 要求。
  4. 狀態數:2^20 = 1,048,576,邊界情況需優化內存(可用 float 或壓縮),但 N≤20 通常 N≤16 實際測試,double dp[1<<20] 約 8MB 可接受。

複雜度

  • 時間:O(N·2^N),N=20 時 ≈ 20M 操作,C++ 1s 內通過。
  • 空間:O(2^N)。

總結

HDU 4336 是「收集期望 + 狀態壓縮 DP」的教科書級題目。核心在於建立期望方程並化簡,分母正是「有效轉移概率」,避免了無效自環的無限級數求和。狀態壓縮將集合狀態映射為整數,配合記憶化搜索或迭代 DP 高效求解。掌握此模板,可解決所有「隨機收集/轉移期望」類問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved