Monty Hall(娱乐节目抽奖游戏)蒙特卡洛模拟:

Monty Hall(娱乐节目抽奖游戏)蒙特卡洛模拟:

1. 模拟背景描述:

1)有x个门,某个门后面有奖,剩余的门后是骆驼。
2)嘉宾选择一个门。
3)主持人打开剩下的x-1个门中的一个,但只能打开无奖的门。
4)此时,主持人问嘉宾要不要换门?还是坚持首次选择?
问题: 嘉宾应不应该换?

2. 蒙特卡洛算法原理:

  基于大数定理与中心极限定理对随机事件进行模拟。

3. 程序分如下几部:

1) 设定奖(即奖分布随机的情况下,嘉宾赢不赢改换)
2)嘉宾选择门号 
3)主持人选择门号(不能是奖门,以及嘉宾选择的门)
4)不换赢的概率,换赢的概率。
5)模拟x次

4. python实现

import os
import random
from __future__ import division

#生成连续的整型序列
def intSeq(num):
    seq=[]
    for i in range(num):
        seq.append(i+1)
    return seq

#随机生成有奖的门号
def getPrize(num):
    prize=random.choice(intSeq(num))
    return prize    

#嘉宾选择
def getChoicebyGuest(num):
    guest=random.choice(intSeq(num))
    return guest

#主持人选择,不能选择有奖的门和嘉宾已选择的门
def getChoicebyHost(prize,guest,num):
    choice_set=intSeq(num)
    if prize in choice_set:
        choice_set.remove(prize) 
    if guest in choice_set:
        choice_set.remove(guest)
    host=random.choice(choice_set)
    return host

#  嘉宾不换与换,是否赢
def isWin(prize,guest,host,num):
    choice_set=intSeq(num)
    if guest in choice_set:
        choice_set.remove(guest)
    if host in choice_set:
        choice_set.remove(host)   
    is_notchange_win=0
    is_change_win=0
    if prize==guest:
        is_notchange_win=1
    change_num=random.choice(choice_set) #如果换,除嘉宾和主持人门号外,剩下随机选择一个
    if prize==change_num:
        is_change_win=1
    return is_notchange_win,is_change_win,change_num

#多次模拟
def testPro(times,num):
    result=[]
    for i in range(times):
        prize=getPrize(num)# 选取有奖门号
        guest=getChoicebyGuest(num) #嘉宾选择门号
        host=getChoicebyHost(prize,guest,num) #主持人选择门号
        is_notchange_win,is_change_win,change_num=isWin(prize,guest,host,num) #换与不换是否赢。
        test_result=','.join([str(prize),str(guest),str(host),str(change_num),str(is_notchange_win),str(is_change_win)])
        result.append(test_result)
    return result

#设定场景,例如:嘉宾选1号门,主持人选3号门时,根据换与不换赢的概率决定是否要换。
def winPro(guest_choice,host_choice,result):
    chage_flag=0 #要不要换门号(如果换后赢的概率大于未换的概率,则换门号)
    times_item=0 #模拟多次中某一场景出现的次数,例如:模拟100万次,嘉宾选1号门,主持人选3号门,该场景出现的次数。
    no_change_win=0 #不换,赢标志
    change_win=0 #换,赢标志
    for i in range(len(result)):
        test_result=result[i].split(',')
        if int(test_result[1])==guest_choice and int(test_result[2])==host_choice: #符合指定场景
            times_item=times_item+1
            if int(test_result[4])==1:
                no_change_win=no_change_win+1 #该场景下,不换赢的次数
            if int(test_result[5])==1:
                change_win=change_win+1 #该场景下,换赢的次数。
    no_change_pro=no_change_win/times_item #不换赢概率
    change_pro=change_win/times_item #换赢概率
    if change_pro>no_change_pro: #如果换赢的概率大于不换赢的概率,则换。
        chage_flag=1    
    return no_change_pro,change_pro,chage_flag,times_item

if __name__=='__main__':
    door_num=4 #门的个数
    times=1000000 #模拟次数
    result=testPro(times,door_num)
    for i in range(1,door_num+1): #遍历所有可能出现的场景
        for j in range(1,door_num+1):
            if i<>j: #嘉宾和主持人选择不能一样。
                no_change_pro,change_pro,chage_flag,times_item=winPro(i,j,result)
                print ('test_times:%d'%times_item,'guest: %d'%i,'host:%d'%j,'%d'%chage_flag,'%.2f'% change_pro,'%.2f'% no_change_pro)

5、效果

1)以逗号间隔,各字段含义 test_times:该场景出现次数,guest: 该场景嘉宾选择门号,host:该场景主持人选择门号,换,换赢的概率,不换赢的概率
例如: 总共4道门,模拟100万次,嘉宾选择1号门,主持人选择2号门时,嘉宾【换】赢的概率大(0.37>0.25)。

('test_times:82806', 'guest: 1', 'host:2', '1', '0.37', '0.25')
('test_times:83364', 'guest: 1', 'host:3', '1', '0.37', '0.25')
('test_times:83230', 'guest: 1', 'host:4', '1', '0.37', '0.25')
('test_times:83372', 'guest: 2', 'host:1', '1', '0.37', '0.25')
('test_times:83506', 'guest: 2', 'host:3', '1', '0.38', '0.25')
('test_times:83529', 'guest: 2', 'host:4', '1', '0.37', '0.25')
('test_times:83427', 'guest: 3', 'host:1', '1', '0.37', '0.25')
('test_times:83247', 'guest: 3', 'host:2', '1', '0.37', '0.25')
('test_times:83327', 'guest: 3', 'host:4', '1', '0.38', '0.25')
('test_times:83593', 'guest: 4', 'host:1', '1', '0.37', '0.25')
('test_times:83405', 'guest: 4', 'host:2', '1', '0.38', '0.25')
('test_times:83194', 'guest: 4', 'host:3', '1', '0.38', '0.25')
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值