我认为你可以用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。由于我们在叶子节点,声明输出即2
如果v=210:向左走,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))。