我有一个加权的有向图,它有大约20,000个节点。
我学习yesterday关于模拟滚动加权骰子的alias method,这与做出一个选择相同(每个节点是一个加权骰子,而侧面对应于其他节点)。一卷是高效的,但更新权重不是;别名方法可能不合适,因为我将更新骰子而不是我要滚动!
我应该使用哪种数据结构,以便进行频繁更新,以及最适合做出选择的相应算法?
一些想法/说明:
事实是,在实践中我不需要经常做出选择(每分钟不超过一次),所以我不需要最有效的解决方案。但这是一个有趣的副项目,我有兴趣找到一个理论上最优的解决方案。
答案 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))。