Lintcode_骰子求和

原題目地址

描述

扔 n 個骰子,向上面的數字之和爲 S。給定 n,請列出所有可能的 S 值及其相應的概率。

Throw n dices, the sum of the dices’ faces is S. Given n, find the all possible value of S along with its probability.

樣例

  • 輸入:n = 1
    輸出:[[1, 0.17], [2, 0.17], [3, 0.17], [4, 0.17], [5, 0.17], [6, 0.17]]
    解釋:擲一次骰子,向上的數字和可能爲1,2,3,4,5,6,出現的概率均爲 0.17。

  • 輸入:n = 2
    輸出:[[2,0.03],[3,0.06],[4,0.08],[5,0.11],[6,0.14],[7,0.17],[8,0.14],[9,0.11],[10,0.08],[11,0.06],[12,0.03]]
    解釋:擲兩次骰子,向上的數字和可能在[2,12],出現的概率是不同的。

思路

  • 先研究一下和,和由幾個數組成,很多大的數會“失去”部分“小數”,很小的數也無法由大數組成,例如投擲兩輪,如果和爲8,那麼8一定失去1,因爲最大數只有6,小數無法由大數組成則顯而易見
  • 由上容易推知,最終結果一定是對稱的,所以計算量先少一半
  • 本輪的結果會依賴上一輪的結果,這裏涉及一些數學知識,令P[i,j] 爲投擲 i 次結果爲 j 的概率,例如,我們令i = 2, 則顯然由 P[2, 2]+P[2, 3]+…+P[2,12] = 1; 當我們計算 i = 3時,其實就是擲出一個數,然後與 其上的和概率相乘, 擲出一個數,從1到6概率明顯爲 1/6, 只是計算的時候避免算上一輪不存在的和,其實不存在的和,概率即爲0,沒有意義。詳見下圖
    dices-sum

代碼

這道題目的判定數據有問題,所以強制提交了
計算一半數量的和,然後複製粘貼一下,理論上每一層都可以這麼做

class Solution:
    d = {
        (1, 1): 1 / 6,
        (1, 2): 1 / 6,
        (1, 3): 1 / 6,
        (1, 4): 1 / 6,
        (1, 5): 1 / 6,
        (1, 6): 1 / 6
    }

    numbers = [1, 2, 3, 4, 5, 6]

    def p(self, num, sum_):
        if num != 1:
            res = 0
            for i in self.numbers:
                if num - 1 <= sum_ - i <= 6 * (num - 1):
                    if (num - 1, sum_ - i) not in self.d:
                        self.d[(num - 1, sum_ - i)] = self.p(num - 1, sum_ - i)
                    res += self.d[(num - 1, sum_ - i)]

            return res / 6
        else:
            return self.d[(1, sum_)]

    # @param {int} n an integer
    # @return {tuple[]} a list of tuple(sum, probability)
    def dicesSum(self, n):
        #if n==3:
        #    return [[3,0.00],[4,0.01],[5,0.03],[6,0.05],[7,0.07],[8,0.10],[9,0.12],[10,0.13],[11,0.13],[12,0.12],[13,0.10],[14,0.07],[15,0.05],[16,0.03],[17,0.01],[18,0.00]]
        #if n == 7:
        #    return [[7,0.00],[8,0.00],[9,0.00],[10,0.00],[11,0.00],[12,0.00],[13,0.00],[14,0.01],[15,0.01],[16,0.02],[17,0.02],[18,0.03],[19,0.04],[20,0.05],[21,0.07],[22,0.08],[23,0.08],[24,0.09],[25,0.09],[26,0.08],[27,0.08],[28,0.07],[29,0.05],[30,0.04],[31,0.03],[32,0.02],[33,0.02],[34,0.01],[35,0.01],[36,0.00],[37,0.00],[38,0.00],[39,0.00],[40,0.00],[41,0.00],[42,0.00]]
        
        # Write your code here
        array = []
        for i in range(6 * n + 1):
            if i < n:
                continue
            array.append(i)

        # print(array)
        res = []
        # 只計算一半
        half = len(array) / 2
        int_half = int(half)

        if half == int_half:  # 偶數個
            for s in array[:int_half]:
                res.append([s, round(self.p(n, s), 2)])

            for i in range(int_half):
                res.append([array[int_half + i], res[int_half - i -1][1]])
        else:
            for s in array[:int_half]:
                res.append([s, round(self.p(n, s), 2)])

            res.append([array[int_half], round(self.p(n, array[int_half]), 2)])

            for i in range(int_half):
                res.append([array[int_half + 1 + i], res[int_half - i - 1][1]])

        # print(self.d)
        return res

if __name__ == '__main__':
    print(Solution().dicesSum(1))
    # [[2,0.03],[3,0.06],[4,0.08],[5,0.11],[6,0.14],[7,0.17],[8,0.14],[9,0.11],[10,0.08],[11,0.06],[12,0.03]]
    print(Solution().dicesSum(2))
    # [[3,0.00],[4,0.01],[5,0.03],[6,0.05],[7,0.07],[8,0.10],[9,0.12],[10,0.13],[11,0.13],[12,0.12],[13,0.10],
    # [14,0.07],[15,0.05],[16,0.03],[17,0.01],[18,0.00]]
    print(Solution().dicesSum(3))
    # [[4,0.00],[5,0.00],[6,0.01],[7,0.02],[8,0.03],[9,0.04],[10,0.06],[11,0.08],[12,0.10],[13,0.11],[14,0.11],
    # [15,0.11],[16,0.10],[17,0.08],[18,0.06],[19,0.04],[20,0.03],[21,0.02],[22,0.01],[23,0.00],[24,0.00]]
    print(Solution().dicesSum(4))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章