使用 Warnsdorff 规则的 Knight' tour 主要给出了奇数大小的错误输出

Knight' tour using Warnsdorff's rule gives wrong output with odd sizes mostly

我写了一个代码来解决knight's tour problem,问题是有时会得到错误的输出。

特别是,非常频繁地使用奇数尺寸的棋盘:例如从位置 [0,1] 开始并使用 5X5 的棋盘它给我:

[[0, 1], [2, 0], [4, 1], [3, 3], [1, 4], [0, 2], [1, 0], [3, 1], [4, 3], [2, 2], [0, 3], [2, 4], [1, 2], [0, 0], [2, 1], [4, 0], [3, 2], [1, 3], [3, 4], [4, 2], [3, 0], [1, 1], [2, 3], [2, 3], [4, 4]]

如您所见,[2,3] 有重复。我检查了我的算法在给定电路板尺寸的情况下得到了多少错误输出,我发现奇数尺寸只有 50% 的时间正确输出,而偶数尺寸大约有 99% 的时间输出正确。怎么可能?

def rule(start , size):
    moves = [start ,]
    plus = [(1, 2), (1, -2), (-1, 2), (-1, -2), (2, 1), (2, -1), (-2, 1), (-2, -1)]
    while 1 == 1 :
        d = 7
        for x in plus:
            s = list(plus)
            c = 0
            q = [ start[0]+x[0] , start[1]+x[1] ]
            if valid(q , size , moves):
                    if len(moves) == size ** 2 -1 :
                        moves.append(q)
                        return moves
                    s.remove((-x[0] , -x[1]))
                    for y in s :
                        p = [ q[0]+y[0] , q[1]+y[1] ]
                        if valid(p , size , moves):
                            c = c+1
                    if 0 < c <= d :
                        l = q
                        d = c
        start = l
        moves.append(start)
        
def valid(q , size , moves):
    if 0 <= q[0] < size  and 0 <= q[1] < size :
        if q not in moves:
            return True
    return False

当所选路径遇到 "dead end" 时会发生这种情况。

在您提到的示例中,起点为 [0,1],大小为 5x5,这发生在选择方块 [2, 3] 时(第一次)。那时只需要再访问 2 个方块。它们是 [0,4] 和 [4,4]。但是这两个方块都没有未访问过的邻居。

因此,对于这两个有效的 q 移动,c 仍然为 0。这意味着 l 的值将 而不是 被设置——它保持其先前的值,仍然是 [2, 3]。因此,当您执行 start = l

时会添加此副本

Warnsdorff 规则并不能绝对保证实现巡回赛。在算法过程中的几个点上,存在平局——具有相等 c 值的移动。在这种情况下,您将使用具有此 c 值的最后一个。但可能你需要从这些关系中选择另一个关系才能获得成功。

所以要么你必须实施一个回溯算法,检测这样的 "dead ends" 并回溯到有平局的地方,然后从那里走另一条路。

或者您应该做一些更复杂的事情,因为似乎有一些方法可以从平局中选择 "right" 一步。请参阅 Wikipedia 以参考两篇描述成功打破平局方法的文章。