刷題32——面試題60:n個(gè)骰子的點(diǎn)數(shù)

題目:

把n個(gè)骰子扔在地上,所有骰子朝上一面的點(diǎn)數(shù)之和為s。輸入n,打印出s的所有可能的值出現(xiàn)的概率。

骰子一共有6個(gè)面,每個(gè)面上都有一個(gè)點(diǎn)數(shù),對(duì)應(yīng)的是1~6之間的數(shù)字。所以n個(gè)骰子的點(diǎn)數(shù)和的最小值為n,最大值為6n.另外,根據(jù)排列組合的知識(shí),我們還知道n個(gè)骰子的所有點(diǎn)數(shù)的排列數(shù)位6n。要解決這個(gè)問(wèn)題,我們需要先統(tǒng)計(jì)出每個(gè)點(diǎn)數(shù)出現(xiàn)的次數(shù),然后把每個(gè)點(diǎn)數(shù)出現(xiàn)的次數(shù)除以6n,就能求出每個(gè)點(diǎn)數(shù)出現(xiàn)的概率。

思路一:基于遞歸求骰子點(diǎn)數(shù),時(shí)間效率不夠高

現(xiàn)在我們考慮如何統(tǒng)計(jì)每個(gè)點(diǎn)數(shù)出現(xiàn)的次數(shù)。要想求出n個(gè)骰子的點(diǎn)數(shù)和,可以先把n個(gè)骰子分為兩堆:第一堆只有一個(gè);另一堆有n-1個(gè)。單獨(dú)的那一個(gè)有可能出現(xiàn)16的點(diǎn)數(shù)。我們需要計(jì)算16的每一種點(diǎn)數(shù)和剩下的n~1個(gè)骰子來(lái)計(jì)算點(diǎn)數(shù)和。接下來(lái)把剩下的n-1個(gè)骰子仍然分成兩堆:第一堆只有一個(gè);第二堆有n-2個(gè)。我們把上一輪那個(gè)單獨(dú)骰子的點(diǎn)數(shù)和這一輪單獨(dú)骰子的點(diǎn)數(shù)和相加,再和剩下的n-2個(gè)骰子來(lái)計(jì)算點(diǎn)數(shù)和。分析到這里,我們不難發(fā)現(xiàn)這是一種遞歸的思路,遞歸結(jié)束的條件就是最后只剩下一個(gè)骰子。

我們可以定義一個(gè)長(zhǎng)度位6n-n+1的數(shù)組,將和為s的點(diǎn)數(shù)出現(xiàn)的次數(shù)保存到數(shù)組的第s-n個(gè)元素里

python代碼如下:

class Solution:

    def PrintProb(self, n):
        if n <1:
            return
        g =6
        maxSum =n *g
        pProb =[0]*(maxSum -n +1)
        self.Prob(n, pProb)
        total =6**n
        for i in range(n, maxSum+1):
            ratio =pProb[i-n]/total
            print(i,': ',ratio)
            
    def Prob(self, n, pProb):
        g =6
        for i in range(1, g+1):
            self.Prob2(n, n, i, pProb)
            
    def Prob2(self, ori, cur, sum, pProb):
        g =6
        if cur ==1:
            pProb[sum -ori] +=1
        else:
            for i in range(1, g+1):
                self.Prob2(ori, cur-1, i+sum, pProb)

思路二:動(dòng)態(tài)規(guī)劃

  1. 現(xiàn)在變量有:骰子個(gè)數(shù),點(diǎn)數(shù)和。當(dāng)有c個(gè)骰子,點(diǎn)數(shù)和為k時(shí),出現(xiàn)次數(shù)記為dp(c, k)。那與c-1各骰子階段之間的關(guān)系是怎樣的?

  2. 當(dāng)我有c-1個(gè)骰子時(shí),再增加一個(gè)骰子,這個(gè)骰子的點(diǎn)數(shù)只可能為1、2、3、4、5或6,則有:

    • (c-1, k-1):第c個(gè)骰子投了點(diǎn)數(shù)1

    • (c-1, k-2):第c個(gè)骰子投了點(diǎn)數(shù)2

    • ……

    • (c-1, k-6):第c個(gè)骰子投了點(diǎn)數(shù)6

    在c-1個(gè)骰子的基礎(chǔ)上,再增加一個(gè)骰子出現(xiàn)點(diǎn)數(shù)和為k的結(jié)果只有這6種情況,所以:

    dp(c, k) =dp(c-1, k-1) +dp(c-1, k-2) +dp(c-1, k-3) +dp(c-1, k-4) +dp(c-1, k-5) +dp(c-1, k-6)(注意當(dāng)k<6的處理越界問(wèn)題)

  3. 有一個(gè)骰子:

    dp(1, 1) =dp(1, 2) =dp(1, 3) =dp(1, 4) =dp(1, 5) =dp(1, 6) =1

    因此狀態(tài)轉(zhuǎn)移方程為:

    dp(c)(k) =sum(dp(c-1)(k-m))(1<=m<=g and m<k)

def get_ans(n):
    if n<1:
        return
    total =6**n
    dp =[[0 for i in range(6*n+1)] for j in range(n+1) ]
    for i in range(1,7):
        dp[1][i] =1
    
    for i in range(2, n+1):
        for j in range(2, 6*n+1):
            sum =0
            
            for m in range(1, j):
                if m <=6:
                    sum +=dp[i-1][j-m]
            dp[i][j] =sum
            
    for k in range(n, 6*n+1):
        print(k, ': ', dp[n][k]/total)

更多精彩,關(guān)注“咋家”

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容