• 随机模拟【2】:随机模拟的研究范围和特征-2


    本系列同步发布于本人的知乎专栏:确定性随机

    个人觉得随机模拟有一个很大的优势,那就是用类似于思想实验的方式对理论进行验证,同时也能够解决很多理论上无法最终解析的事情,给出一个近似但很实际用处的结论。

    3. 优惠券收集问题

    曾经在知乎上看过这样一个问题:

    话说古代中国帝王都是后宫佳丽三千,问若每天晚上皇帝都随机地宠幸一位妃嫔,问需要多少天才能将三千妃嫔都宠幸一遍?

    这个问题就是典型的所谓优惠券收集问题。上面那个问题和小时候吃脆面攒齐梁山水浒一百单八将平均需要吃多少包脆面呢。我们可以假设,当前我们已经凑了 n 个水浒人物,假设要抽到 n+1人物,需要再消费 x包干脆面。在消费者 x 包干脆面中,我们抽到重复卡片的概率 :

    P_1 = P( 抽到重复角色)=frac{n}{N},其中 N=108 , P_2 = P(抽到不重复角色)=frac{N-n}{N}

    我们成功抽到 n+1 个人物角色时,一共失败了 x 次,符合几何分布:

    P(n 
ightarrow n+1) = (1-P_2)^x 	imes P_2 Rightarrow E(x) = frac {1} {P_2} = frac { N } {N - n } = frac {108}{108-n}

    所以,你要集齐108个梁山好汉,那么你要吃掉的(或者买)干脆面的数量为:

    S = sum_{i=1}^{107} frac {108}{108-i} = 527 , 

    期望你要吃500多包才能凑够。(同样,我们可以计算那个皇帝宠幸3000妃嫔的题目)。当然,这都是理想情况,我们假设的是每个卡片出现的概率是一样的,但实际情况是商家会故意让某些卡片出现的概率很低,从而就会增加购买的次数。

    现在我们将问题反过来一下,为了简化下问题,我们把问题改为集齐6张优惠券而不是108个英雄好汉卡,现在问题是我买了12包脆面,那么我能够集齐6张优惠券的概率是多少呢?其实这个是一个累计概率的计算问题,设 P_i 为第 i 次集齐6张优惠券的概率,显然有 i geq 6 ,于是我们的原问题就是求解:

    P (X = 集齐6张优惠)= sum_{i=6}^{12} P_i

    这个问题直接求解的难度较高,我们可以用随机模拟的方式来解决这个问题。我们考虑1-6为数字平均分布,每次连续获取12个随机数,如果这12个随机数里面包含完整的1-6共6个数字,那么就认为这12次的抽券获得了完整的优惠券组合。Python代码如下(虽然这本书要求使用的是Matlab,这个我之后再了解下吧:P):

    import numpy as np
    
    def simulate_lottery(num_of_take):
        ret = 0
        upper = 6 # 完整优惠券组合的数量
        lottery_number_set = set()
        for n in range(num_of_take):
            rand_lottery_number = np.random.randint(1,upper+1)
            lottery_number_set.add(rand_lottery_number)
        len_of_set = len(lottery_number_set)
        if len_of_set == 6:
            ret = 1
            print "collect a different cards"
        else:
            ret = 0
            print "this card is what i have already owned"
        return ret
    
    num_of_experiences = 1000 
    num_of_lottery_to_take = 12 #抽取优惠券的次数##
    completed_collect = 0
    
    for i in range(num_of_experiences):
        completed_collect += simulate_lottery(num_of_lottery_to_take)
    print completed_collect

    重复做了1000次实验,得到的结果是431, 也就是说连续抽12次,能够集齐优惠券的概率大概是43.1%。下面的问题是,随着抽的次数增加,能够集齐优惠券的概率是如何变化的呢。对上面的代码稍微修改下:

     1 # -*- coding: utf-8 -*-
     2 import numpy as np
     3 
     4 def simulate_lottery(num_of_take):
     5     ret = 0
     6     upper = 6
     7     lottery_number_set = set()
     8     for n in range(num_of_take):
     9         rand_lottery_number = np.random.randint(1,upper+1)
    10         lottery_number_set.add(rand_lottery_number)
    11     len_of_set = len(lottery_number_set)
    12     if len_of_set == 6:
    13         ret = 1
    14         print "collect a different cards"
    15     else:
    16         ret = 0
    17         print "this card is what i have already owned"
    18     return ret
    19 
    20 num_of_experiences = 1000
    21 #num_of_lottery_to_take = 12
    22 completed_collect = 0
    23 pro_ret = {}
    24 
    25 for num_of_lottery_to_take in [12,20,25,35,45,50,60]: #定义抽取的次数
    26     for i in range(num_of_experiences):
    27         completed_collect += simulate_lottery(num_of_lottery_to_take)
    28     pro_ret[num_of_lottery_to_take] = completed_collect 
    29 print pro_ret

    结果是:

    {35: 982, 12: 421, 45: 998, 50: 1000, 20: 846, 25: 956, 60: 1000}

    可见,抽到25次以后,能收集完整奖券的概率已经升到95.6%。

  • 相关阅读:
    Java基础学习笔记类的静态属性和静态方法待继续补充
    Java基础学习笔记常量与变量♪(^∇^*)
    从01超详细教你实现前端读取excel表格并渲染到界面
    Java基础学习笔记Java数据类型转换(~ ̄▽ ̄)~
    umi项目打包优化 广东靓仔
    快速构建前端错误监控系统 广东靓仔
    用canvas给背景添加音符 广东靓仔
    JS实现继承 广东靓仔
    vscode 好用插件 广东靓仔
    前端手写代码题库 广东靓仔
  • 原文地址:https://www.cnblogs.com/zhanghaohong/p/9656115.html
Copyright © 2020-2023  润新知