假设有一副54张牌的扑克,每次有放回的抽取一张,当每张牌都至少抽取一次之后总的抽取次记为x, 求x的期望值
蒙特卡洛模拟python版本:
import random import time begin_time = time.perf_counter() result_num = [] cards_num = list(range(54)) for i in range(1000000): result = [] count = 0 while len(result) < 54: num = random.choice(cards_num) if num not in result: result.append(num) count += 1 result_num.append(count) end_time = time.perf_counter() print("运算耗费的时间为:{}".format(end_time - begin_time)) print("平均期望为:{}".format(sum(result_num)/len(result_num)))
运算耗费的时间为:440.74856580002233
平均期望为:247.005991
蒙特卡洛模拟c++版本:
#include <iostream> #include <vector> #include <algorithm> #include <random> #include <numeric> #include <chrono> int main() { // 获取起始时间点 auto start = std::chrono::high_resolution_clock::now(); std::vector<int> result_num; std::vector<int> cards_num(54); std::iota(cards_num.begin(), cards_num.end(), 0); // Fill with numbers from 0 to 53 // Random number generator std::random_device rd; std::mt19937 gen(rd()); for (std::size_t i = 0; i < 1000000; ++i) { std::vector<int> result; result.reserve(54); // Reserve space for 54 cards int count = 0; while (result.size() < 54) { std::uniform_int_distribution<> dis(0, 53); int num = dis(gen); //std::cout << "num = " << num << std::endl; if (std::find(result.begin(), result.end(), num) == result.end()) { result.push_back(num); } ++count; } result_num.push_back(count); } // Calculate the average double sum = std::accumulate(result_num.begin(), result_num.end(), 0LL); double average = sum / result_num.size(); // 获取结束时间点 auto end = std::chrono::high_resolution_clock::now(); // 计算耗时 std::chrono::duration<double> duration = end - start; // 输出耗时,单位为秒 std::cout << "Function execution time: " << duration.count() << " seconds" << std::endl; std::cout << "average : " << average << std::endl; return 0; }
Function execution time: 78.02 seconds
average : 247.033
c++版本只有python版本的5-6倍,看起来c++版本写的效率不怎么高。
chatgpt的答案:
然后我们乘以54:
E(T54)=54×4.565≈246.51
因此,所有54张牌至少被抽取一次所需的抽取次数的期望值大约是 246.51 次。
总结
在有放回地抽取54张牌,直到每张牌都至少被抽取一次的情况下,总的抽取次数的期望值约为 246.51 次。