概率問題的解決和隨機算法的實現

在解決一些問題時,往往需要一些隨機數或者隨機數組的輸出,這時候就需要能夠輸出隨機數的函數或者能打亂輸入的值的順序得到隨機數列的函數或者說算法。
各個編程語言基本都有自己內置的的隨機數生成函數,具體原理可以自行了解,只要會用就可以了,本文主要關注利用這個基本的隨機數生成函數設計的一些隨機算法的實現和利用這樣的算法用程序解決生日悖論這樣的問題。
1、隨機排列數組的兩種算法的實現
①一種方法是利用隨機數生成函數對數組的每個元素重新設置一個序號,在新的數組中將這些數字按照生成的序號的順序進行重新排序,達到隨機排列數組的效果。
具體的python實現如下。

import random
def random_sort(list0):
    n=len(list0)
    list1=[]
    for i in range(len(list0)):
        k=random.randint(0,n-1)
        list1.append(list0[k])
        del(list0[k])
        n=n-1
    return list1

可以看出,這種算法對於長度爲n 的數組需要大小爲n 的輔助空間,時間複雜度爲Θn
②另一種方法就是放棄另建一個數組,直接在原數組上對元素順序進行隨機調換。
具體的python實現如下。

def random_switch(list0):
    n=len(list0)
    for i in range(n):
        k=random.randint(i,n-1)
        swap=list0[i]
        list0[i]=list0[k]
        list0[k]=swap
    return list0

可以看出,這種算法只需要大小爲1 的輔助空間,時間複雜度也爲Θn
2、解決生日悖論問題
生日悖論問題:最少需要多少人就能使得其中兩個人的生日相同的概率達到50%?
這個問題的答案其實要遠遠小於一年的的天數365,遠小於這個數的一半,這個問題的答案是23。也就是說隨機抽取23人就可以讓其中有兩人的生日相同的概率達到50%。
這個問題的數學解法這裏就不介紹了,但我們在對數學概率知識不精通的情況下完全可以編寫程序來得到23這個答案。
首先,利用程序解決這個問題的主要依據是大數原理,即當實驗次數夠多的時候,事件發生的頻率的算數平均數會趨近理論概率,即最終收斂於理論上的概率。
其次,如何解決兩人的生日相同的概率的表示問題。在一次實驗中,我們可以將事件發生了表示爲1 ,事件未發生表示爲0,最後對這些值進行累加併除以總的實驗次數,即可得到發生的頻率的算數平均值。
具體python實現代碼如下。

#從list0中隨機選出需要的n個人
def people_take(list0,n):
    n0=len(list0)
    list1=[]
    #通過循環n次得到選出的n個人的數組list1
    for i in range(n):
        k=random.randint(0,n0-1)
        list1.append(list0[k])
    return list1

#對判定事件“有兩個人的生日相同”事件是否發生
def random_count(list0):
    n0=len(list0)
    set0=set(list0)
    n1=len(set0)
    sum0=0
    #如果有生日一樣的人,則sum0=1,否則sum0=0
    if n1<n0:
        sum0=1
    return sum0

#主函數,basic_number爲基數,即生日可能的數量365,people_number爲選出作爲樣本的人數
#circle_number爲循環次數,即實驗進行的次數
def find_number(basic_number,people_number,circle_number):
    list_origin=[x for x in range(basic_number)]
    people_result=0
    dirc={}
    for people in range(5,people_number):
        sum=0
        for circle in range(circle_number):
            #將生日的數組亂序排列
            list_origin=random_switch(list_origin)
            #從打亂的生日數組中隨機取出n個樣本,雙重隨機保證樣本數據的隨機性
            list_get=people_take(list_origin,people)
            sum=sum+random_count(list_get)
        #circle_number次實驗後得出的時間發生頻率的算數平均數result
        result=sum/circle_number
        #將樣本人數和得出的有兩人相同生日的概率存入字典,方便查看
        dirc.update({people:result})
    return dirc

最終以實驗次數爲10000次進行實驗,得出如下的結果。

find_number(365,50,10000)
{5: 0.0286,
 6: 0.0424,
 7: 0.0578,
 8: 0.0706,
 9: 0.0963,
 10: 0.1128,
 11: 0.1438,
 12: 0.1722,
 13: 0.1991,
 14: 0.2241,
 15: 0.2477,
 16: 0.2862,
 17: 0.3111,
 18: 0.3464,
 19: 0.3779,
 20: 0.4101,
 21: 0.4452,
 22: 0.4653,
 23: 0.5036,
 24: 0.5469,
 25: 0.5714,
 26: 0.6011,
 27: 0.6242,
 28: 0.6516,
 29: 0.6773,
 30: 0.7035,
 31: 0.7282,
 32: 0.7553,
 33: 0.7739,
 34: 0.7916,
 35: 0.8217,
 36: 0.8334,
 37: 0.8558,
 38: 0.8682,
 39: 0.8751,
 40: 0.8925,
 41: 0.9023,
 42: 0.9132,
 43: 0.9261,
 44: 0.9273,
 45: 0.941,
 46: 0.9451,
 47: 0.951,
 48: 0.9595,
 49: 0.9615}

可以看出,當人數達到23人時,10000次的實驗表明可以使其中兩個人的生日相同的機會達到50%,而當人數達到48人時,有超過95%的可能性使得有兩人的生日相同。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章