请解释一下这个算法的流程及其工作原理?(Knuth Topological Sorting)

时间:2014-09-21 15:42:05

标签: algorithm

给定{1 .... n}上的关系〜具有x~y暗示x&lt; y,这个算法生成所有排列a [1] .... a [n]并且它们反转a&#39; [1] ..... a&#39; [n]具有a&#39; [ j]&lt;每当j~k时a&#39; [k]。为方便起见,我们假设a [0] = 0且0≤k表示1 <= k <= n。

V1。 [初始化。]设置a [j]&lt; - j和a&#39; [j]&lt; -j为0&lt; = j&lt; = n。

V2。 [访问。]访问排列a [1] ... a [n]及其逆a&#39; [1] ... a&#39; [n]。然后设置k&lt; - n。

V3。 [可以向左移动吗?]设置j&lt; - a&#39; [k]和l&lt; -a [j-1]。如果l~k,请转到V5。

V4。 [是的,移动它。]设置[j-1]&lt; - k,a [j]&lt; -l,a&#39; [k]&lt; -j-1和&#39; [l] &lt; - j。转到V2。

V5。 [不,把k放回去。]当j&lt; k,设置l&lt; -a [j + 1],a [j]&lt; -1,a&#39; [l]&lt; -j,并且j&lt; -j + 1。     然后设置[k]&lt; -a&#39; [k]&lt; -k。如果k> 1,则将k减1并返回V3。 0

已经尝试过实施但是与流程混淆了。请解释此算法的流程及其如何工作基于优先约束,例如1~2表示{1,2,3}。

1 个答案:

答案 0 :(得分:0)

Knuth,祝福他,是一位未经构建的汇编语言程序员。以下是将此算法呈现为经过测试的无goto Python。 precedes是关系~

from itertools import permutations


def topological_orders(n, precedes):
    a = list(range(n + 1))
    ai = a[:]
    while True:
        yield tuple(a[1:])
        k = n
        while True:
            j = ai[k]
            l = a[j - 1]
            if not precedes(l, k):
                a[j - 1] = k
                a[j] = l
                ai[k] = j - 1
                ai[l] = j
                break
            while j < k:
                l = a[j + 1]
                a[j] = l
                ai[l] = j
                j += 1
            a[k] = ai[k] = k
            k -= 1
            if not k > 0:
                return


def test(n, precedes):
    fast_orders = set()
    for order in topological_orders(n, precedes):
        print(order)
        fast_orders.add(order)
    slow_orders = set()
    for order in permutations(range(n + 1)):
        if not any(precedes(order[i], order[j]) for i in range(n + 1) for j in range(i)):
            slow_orders.add(order[1:])
    assert fast_orders == slow_orders


if __name__ == '__main__':
    def divides(a, b):
        return a < b and (a == 0 or b % a == 0)

    test(6, divides)

在您的输入中,我们从

开始
0123.

访问123并向左移动3

0132

访问132并向左移动3

0312

访问312。我们无法移动3,因为0 ~ 3。将其一直向右移动并尝试移动2

0123

我们无法移动2,因为1 ~ 2。尝试移动1。我们无法移动1,因为0 ~ 1。尝试移动0 - 哎呀,我们已经完成了。