加载骰子的数据结构?

时间:2011-02-17 10:33:44

标签: algorithm language-agnostic data-structures random probability

假设我有一个n侧加载的模具,其中每个侧面k在我滚动时有一些概率p k 。我很好奇是否存在静态存储该信息的良好算法(即对于一组固定的概率),以便我可以有效地模拟模具的随机滚动。

目前,我有一个针对此问题的O(lg n)解决方案。想法是存储所有k的前k个边的累积概率的表,它们生成范围[0,1)中的随机实数并且对表执行二元搜索以获得其累积的最大索引值不大于所选值。我更喜欢这个解决方案,但运行时没有考虑概率似乎很奇怪。特别是,在一方总是出现或者值均匀分布的极端情况下,可以使用朴素的方法在O(1)中生成滚动的结果,尽管我的解决方案仍然需要对数多步。 / p>

有没有人对如何以某种方式在运行时“自适应”的方式解决这个问题有任何建议?

编辑:根据这个问题的答案,我写了 an article describing many approaches to this problem ,以及他们的分析。看起来Vose的别名方法的实现给出了Θ(n)预处理时间和每次掷骰的O(1)时间,这确实令人印象深刻。希望这是对答案中包含的信息的有用补充!

4 个答案:

答案 0 :(得分:111)

您正在寻找alias method,它提供 O(1)方法来生成固定离散概率分布(假设您可以在恒定时间内访问长度为n的数组中的条目)一次性O(n)设置。您可以在Luc Devroye的chapter 3 (PDF) "Non-Uniform Random Variate Generation"中找到它。

我们的想法是将你的概率数组p k 并产生三个新的n元素数组,q k ,一个 k ,和b k 。每个q k 是介于0和1之间的概率,并且每个 k 和b k 是1和n之间的整数。

我们通过在0和1之间生成两个随机数r和s来生成1到n之间的随机数。设i = floor(r * N)+1。如果q i < s然后返回 i else返回b i 。别名方法中的工作是弄清楚如何产生q k k 和b k

答案 1 :(得分:4)

使用平衡二叉搜索树(或数组中的二进制搜索)并获得O(log n)复杂度。每个芯片结果都有一个节点,并且键是触发该结果的间隔。

function get_result(node, seed):
    if seed < node.interval.start:
        return get_result(node.left_child, seed)
    else if seed < node.interval.end:
        // start <= seed < end
        return node.result
    else:
        return get_result(node.right_child, seed)

这个解决方案的优点是实现起来非常简单,但仍然具有很好的复杂性。

答案 2 :(得分:3)

我正在考虑制作你的餐桌。

您可以创建一个长度为xN的整数数组,而不是使用具有每个骰子值累积的表格,其中x理想情况下是一个高数字,以提高概率的准确性。

使用索引(由xN标准化)填充此数组作为累积值,并且在数组中的每个“槽”中,如果此索引出现,则存储可能的骰子卷。

也许我可以用一个例子来解释:

使用三个骰子:P(1)= 0.2,P(2)= 0.5,P(3)= 0.3

创建一个数组,在这种情况下我会选择一个简单的长度,比如10.(即x = 3.33333)

arr[0] = 1,
arr[1] = 1,
arr[2] = 2,
arr[3] = 2,
arr[4] = 2,
arr[5] = 2,
arr[6] = 2,
arr[7] = 3,
arr[8] = 3,
arr[9] = 3

然后获得概率,只需随机化0到10之间的数字,然后只需访问该索引。

这种方法可能会失去准确性,但增加x和准确度就足够了。

答案 3 :(得分:1)

有很多方法可以生成具有自定义分布(也称为离散分布)的随机整数。选择取决于许多因素,包括要选择的整数数量,分布的形状以及分布是否会随时间变化。

使用自定义权重函数f(x)选择整数的最简单方法之一是拒绝采样方法。以下假设f的最大可能值为max。平均而言,拒绝采样的时间复杂度是恒定的,但在很大程度上取决于分布的形状,并且永远无法运行。要使用拒绝采样在[1,k]中选择一个整数:

  1. 在[1,i]中选择一个统一的随机整数k
  2. 以概率f(i)/max,返回i。否则,请转到步骤1。

其他算法的平均采样时间并不非常依赖于分布(通常是常数或对数),但是通常需要您在设置步骤中预先计算权重并将其存储在数据结构中。就它们平均使用的随机比特数而言,其中一些也是经济的。这些算法中的许多算法是在2011年之后引入的,其中包括-

  • Bringmann-Larsen简洁的数据结构(“来自离散分布的简洁抽样”,2012年),
  • 唐云鹏的多级搜索(“改变离散分布的随机抽样方法的实证研究”,2019年)和
  • Fast Loaded Dice Roller(2020年)。

其他算法包括 alias方法(您的文章中已经提到),Knuth-Yao算法,MVN数据结构等。请参阅我的“ A Note on Weighted Choice Algorithms”部分进行调查。