随机拓扑排序在近线性时间内均匀分布

时间:2016-07-24 10:31:19

标签: algorithm random topological-sort uniform-distribution

我想要一种拓扑排序算法,每次都不提供相同的排序,但是随机排序,每个排序与所有其他排序同样可能。

生成所有可能的拓扑排序并随机选择一个是正确的,但是太慢了。生成所有排列并过滤无效的拓扑排序也非常慢;如果树/森林足够宽,则第一个降级为第二个。

将新节点插入要检查的节点队列中的随机位置似乎会产生偏差结果,并将其放在最后并进行渔民洗牌似乎也有偏见,因为两者都未能解释节点数"隐藏"在每个节点下,即有多少节点依赖于被调度的import { router as indexRoute } from './routes/index_route'; ab可能没有孩子,而a则拥有树的其余部分。

如何在接近线性的时间内生成随机拓扑排序,每个有效排序具有相同的可能性?

1 个答案:

答案 0 :(得分:1)

编辑:在任何合理的时间内无法按照您希望的方式解决此问题。这样做涉及解决#P完全问题。最好的办法是使用概率方法。

https://mathoverflow.net/questions/45875/how-can-you-compute-the-number-of-topological-sorts-in-a-dag

  1. 提出所有边缘列表
  2. 确定哪些节点是“开始”节点。开始节点没有定向边缘
  3. 对于每个起始节点,选择它,删除与其对应的所有有向边,然后考虑可能的下一个移动的数量。一旦找到每个起始节点的可能移动数,就根据其概率随机选择一个节点(下面给出一个例子)。
  4. 删除起始节点指向的边缘。
  5. 重复步骤2到4。
  6. 这类似于Kahn的算法。

    https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm

    只要从所有其他起始节点中随机选取每个起始节点,就应该得到一个随机有效的拓扑排序,其概率与任何其他随机拓扑排序相同。

    例如,如果我有一个图{(5,11)(7,8)(7,11)(3,8)(3,10)(8,9)(11,2)(11, 9)(11,10)}其中(a,b)是从a到b的有向边,我首先确定5,7和3是起始节点。我会随机选择一个(3),然后从3开始删除所有边,包括(3,8)和(3,10)。我会检查节点8和10现在是否为启动节点。他们不是。我的起始节点现在是5和7.我会选择另一个随机起始节点(7),然后删除7的所有边,即(7,8)和(7,11)。我会检查这些是否是启动节点。 8是起始节点。我的起始节点现在是5和8.我随机选择8,用8删除边,其中包括(8,9)。我检查9是否是一个起始节点。我唯一的开始节点是5.我选择5,删除边缘(5,11)。 11现在是我唯一的开始节点。我选11,去掉边缘(11,2),(11,9)和(11,10)。现在,2,9和10是起始节点。我随机挑选2个,删除所有边缘。 9和10是我的开始节点。我选10,然后9。

    我的拓扑排序现在是{3,7,8,5,11,2,10,9}

    编辑:查找有效拓扑排序的数量似乎是#P-complete,这意味着您最好的选择是使用概率算法来确定每个元素的可能排序数量,然后根据所有起始节点的拓扑排序总数调整概率。

    https://mathoverflow.net/questions/45875/how-can-you-compute-the-number-of-topological-sorts-in-a-dag

    https://en.wikipedia.org/wiki/Sharp-P-complete

    编辑您可以猜测从特定起始节点开始的拓扑排序的分数,方法是选择该起始节点,移除所有起始节点,然后计算所有可能的下一个移动的数量,然后找到一个很好的功能来模拟它。例如,在我的例子中,如果我选择了5,我接下来会有两个可能的移动,3和7.如果我选择了3或7,我还有两个可能的移动。然后我会找出我剩下的可能动作的一小部分,然后概率地选择一个。在这种情况下,所有三个都有相同的机会,所以我只是随机选择一个。在这种情况下,我选择3.然后我可以选择5或7.如果我选择5,我将只剩下一个可能的移动,7,如果我选择7,我将剩下两个可能的移动。因此,有2/3的机会被挑选,5有1/3的几率。这个过程一直持续到你结束。这只是一种启发式方法,但它应该能够让您接近完全随机的有效拓扑排序。此外,在您给出的反例中,为每个起始节点添加一个可能的移动数似乎得到了更好的近似。