通过频繁更新,有效地模拟滚动加权骰子(或遍历加权图)

时间:2012-01-06 18:23:02

标签: c algorithm data-structures graph-theory

我有一个加权的有向图,它有大约20,000个节点。

  1. 给定图中的节点,我随机选择一个相邻节点,其概率与相对权重相关。
  2. 在每次选择之后,我会收到有关选择是好还是坏的反馈,并更新网络。例如,在选择错误后,我会减少指向所选节点的所有边的权重。
  3. 我学习yesterday关于模拟滚动加权骰子的alias method,这与做出一个选择相同(每个节点是一个加权骰子,而侧面对应于其他节点)。一卷是高效的,但更新权重不是;别名方法可能不合适,因为我将更新骰子而不是我要滚动!

    我应该使用哪种数据结构,以便进行频繁更新,以及最适合做出选择的相应算法?


    一些想法/说明:

    • 我可以通过记录每个权重调整来减少更新,然后仅在必要时(即直接在滚动之前)实际更新节点/模具。但我仍然会为每个 roll预先计算一次别名数据。
    • 相反,我可以简单地存储图形(以便更新便宜)并放弃别名方法。我会在每次滚动之前动态计算相对权重(二分搜索在这里工作)。
    • 动态计算相对权重的另一个好处是,我可以将每个节点的“全局权重”分解出来,以进一步减少更新。然后,错误的选择将导致仅2次更新:传入边缘权重和节点的全局权重。
    • 添加:也许介于两者之间:在数据结构中维护本地相对权重的方法(例如树或别名方法),然后在每次滚动时将它们与“全局权重”合并在一起苍蝇。

    事实是,在实践中我不需要经常做出选择(每分钟不超过一次),所以我不需要最有效的解决方案。但这是一个有趣的副项目,我有兴趣找到一个理论上最优的解决方案。

1 个答案:

答案 0 :(得分:1)

我认为你可以用log(k)复杂度做到这一点,其中k是骰子中的面数。

对于一个特定节点,让p1,p2,...,pk为相对概率。设p1 + p2,...,+ pk = p。

构造一个树结构,将这些相对概率作为叶子。每个非叶节点的父节点是其子节点的相对概率之和。 “掷骰子”在0和p之间绘制一个随机值,并在树中跟随它。当您想要更新骰子面的相对概率时,只需更改相应的叶节点值并将其传播到树中。

通过这种方式,您可以选择一个带有一个随机数的随机值,其中需要log(k)步骤来查找与随机数对应的叶子,当您更新一个叶子时,需要log(k)时间来更新树

这是一个非常简单的解决方案描述,如果您需要完整描述,请告诉我。我确信它有效,但不确定这是否足以满足您的需求。

总结一下,这个算法需要: 1. 0和p之间只有一个随机数 2. O(log(k))复杂度“滚动骰子”(即找到下一个节点),其中k是骰子中的面数 3. O(log(k))以“更新给定节点的骰子”。如果原始节点有m个边,则复杂度为O(log(k1))+ O(log(k2))... O((km))其中k1,k2,... km是相邻的连通性节点

====Tree Example====

如果骰子有4个面,且相对概率为1:50,则2:80,3:20,4:70构建树如下:

          220
       /       \
    130         90
   /   \      /    \
 50    80    20    70
  |    |     |      |
  1    2     3      4

生成0到220之间的随机数v。如果是v = 100:采取左路线(从100 <130)然后采取正确的路线(从100> 80)并更新v = v-80 = 20.因为我们在叶子申报o / p即2

如果v = 210:left且v = v-130 = 80,则左v = v-70 = 10,返回叶= 4

如果4更改为60,则更改70到60,90到80和220到210。

==== Lazy update variation ====

每当更改权重时,请勿立即更新树。相反,只需将其标记为“脏重”等待,直到您需要从此特定节点进行预测。

当您需要从特定节点进行预测时,如果某些权重是脏的,则a。仅使用脏节点或b更新树。更新整棵树。如果脏权重的数量是t和总权重数k,如果t * log(k)< k,然后只更新对应于脏权重的树(t * O(k)),否则更新整个树(O(k))。