dqjl0906 2018-06-05 00:09
浏览 68
已采纳

计算掷骰子的概率(非指数时间内)

Variations on this are pretty common questions, but all my google-fu has left me stumped. I would like to calculate the odds of a fair dice roll, but I want to do it efficiently. There are lots of examples out there of how to do this, but all the algorithms I've found are too computationally expensive (exponential time) to work for large numbers of dice with many sides.

The Simple Problem: Calculate the odds of a roll of n, on x y sided dice.

The Simple Solution: Create the n-ary Cartesian product of the roll, sum each product, count the number of times the sum is the target, do a little division and voila.

Example of a Simple Solution in Go: https://play.golang.org/p/KNUS4YBQC0g

The Simple Solution works perfectly. I extended it to allow for cases like dropping the highest/lowest n faces, and the results hold up to spot testing.

But consider {Count: 20,Sides: 20,DropHighest: 0,DropLowest:0, Target: 200}.

If I evaluated that with the previous solution, my "table" would have 104 some odd septillion cells and will max the CPU pretty easily.

Is there a more efficient way to calculate probability for large numbers of dice with many sides? If so, can it account for more complex selection of "success" conditions like dropping some dice?

I'm convinced it's possible due to the existence of this beautiful website: https://anydice.com/program/969

EDIT:

The solution that worked best for me was David Eisenstat's answer, which I ported to go: https://play.golang.org/p/cpD51opQf5h

  • 写回答

2条回答 默认 最新

  • doqrt26664 2018-06-05 19:43
    关注

    Here's some code that handles dropping low and high rolls. Sorry for switching to Python, but I needed easy bignums and a memoization library to keep my sanity. I think the complexity is something like O(count^3 sides^2 drop_highest).

    The way this code works is to divide the space of possibilities for rolling count dice each with sides sides by how many dice are showing the maximum number (count_showing_max). There are binomial(count, count_showing_max) ways to achieve such a roll on uniquely labeled dice, hence the multiplier. Given count_showing_max, we can figure out how many maxed dice get dropped for being high and how many get dropped for being low (it happens) and add this sum to the outcomes for the remaining dice.

    #!/usr/bin/env python3
    import collections
    import functools
    import math
    
    
    @functools.lru_cache(maxsize=None)
    def binomial(n, k):
        return math.factorial(n) // (math.factorial(k) * math.factorial(n - k))
    
    
    @functools.lru_cache(maxsize=None)
    def outcomes(count, sides, drop_highest, drop_lowest):
        d = collections.Counter()
        if count == 0:
            d[0] = 1
        elif sides == 0:
            pass
        else:
            for count_showing_max in range(count + 1):  # 0..count
                d1 = outcomes(count - count_showing_max, sides - 1,
                              max(drop_highest - count_showing_max, 0),
                              drop_lowest)
                count_showing_max_not_dropped = max(
                    min(count_showing_max - drop_highest,
                        count - drop_highest - drop_lowest), 0)
                sum_showing_max = count_showing_max_not_dropped * sides
                multiplier = binomial(count, count_showing_max)
                for k, v in d1.items():
                    d[sum_showing_max + k] += multiplier * v
        return d
    
    
    def main(*args):
        d = outcomes(*args)
        denominator = sum(d.values()) / 100
        for k, v in sorted(d.items()):
            print(k, v / denominator)
    
    
    if __name__ == '__main__':
        main(5, 6, 2, 2)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥35 平滑拟合曲线该如何生成
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable
  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 自己瞎改改,结果现在又运行不了了
  • ¥15 链式存储应该如何解决
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站