【问题标题】:Does Knight tour Problem solve depend on sequence of knight move?骑士之旅问题的解决是否取决于骑士移动的顺序?
【发布时间】:2022-01-23 01:49:03
【问题描述】:

您好,我目前正在阅读 Geeksforgeeks https://www.geeksforgeeks.org/the-knights-tour-problem-backtracking-1 的骑士之旅问题 我正在自己测试代码,当我更改顺序时 骑士按代码移动

 let xMove = [ 2, 1, -1, -2, -2, -1, 1, 2 ];
 let yMove = [ 1, 2, 2, 1, -1, -2, -2, -1 ];

到这里

let xMove = [1,1,-1,-1,2,2,-2,-2]
let yMove = [2,-2,-2,2,-1,1,-1,1]

问题似乎没有解决。这个问题是否依赖于骑士移动的顺序或者它的原因是什么?据我了解,递归会搜索所有可能的动作,所以应该没有区别吧?

【问题讨论】:

    标签: algorithm recursion knights-tour


    【解决方案1】:

    ...问题似乎没有解决

    这正是Wikipedia上也提到的问题:

    除了最小的棋盘外,对骑士之旅进行暴力搜索是不切实际的。例如,在 8×8 棋盘上大约有 4×1051 个可能的移动序列,而现代计算机(或计算机网络)在如此大的棋盘上执行操作的能力远远超出了设置。

    您从 GfG 引用的实施中的移动顺序是 幸运 顺序。对于您测试过的订单,回溯的数量是巨大的。可以想象,在路径的一开始就采取正确的行动是至关重要的。如果一个早期的动作是错误的,就会在递归树的更深的节点中发生大量的回溯。

    有一种启发式方法大大减少了要考虑的移动次数,大多数时候只有1:这是Warnsdorff's rule

    马被移动,所以它总是前进到马从那里向前移动最少的方格。在计算每个候选方格的向前移动次数时,我们不计算重新访问任何已经访问过的方格的移动。可以有两个或多个选择,其中向前移动的次数相等;有多种方法可以打破这种联系,...

    在 8×8 棋盘的情况下,实际上没有必要打破平局:回溯将解决错误的选择。但是由于现在搜索树很窄,这不会导致很多回溯,即使我们很不幸。

    这是一个可运行的 JavaScript sn-p 中的实现。它有意随机打乱移动列表,并在需要回溯时打印“回溯”,以便您可以尝试不同的运行。这将表明这总是能找到平均几乎没有任何回溯的解决方案:

    class Solver {
        constructor(size) {
            this.size = size;
            this.grid = Array.from({length: size}, () => Array(size).fill(-1));
        }
        toString() {
            return this.grid.map(row => 
                row.map(i => (i + "").padStart(2, "0")).join(" ")
            ).join("\n");
        }
        liberty(x, y) {
            // Count the number of legal moves
            return [...this.getMoveList(x, y)].length;
        }
        *getMoveList(x, y) {
            // Get list of legal moves, in random order
            let moves = [[1, 2], [1, -2], [-1, -2], [-1, 2],
                         [2, -1], [2, 1], [-2, -1], [-2, 1]];
            // Shuffle moves randomly
            for (var i = moves.length - 1; i > 0; i--) {
                var j = Math.floor(Math.random() * (i + 1));
                [moves[i], moves[j]] = [moves[j], moves[i]]; // Swap
            }
            // Yield the valid positions that can be reached
            for (let [moveX, moveY] of moves) {
                if (this.grid[x + moveX]?.[y + moveY] == -1) {
                    yield [x + moveX, y + moveY];
                }
            }
        }
        getBestMoveList(x, y) {
            // Get list of move(s) that have the least possible follow-up moves
            let minLiberty = 100000;
            const bestMoves = [];
            // Consider every legal move:
            for (let [nextX, nextY] of this.getMoveList(x, y)) {
                let liberty = this.liberty(nextX, nextY);
                if (liberty < minLiberty) {
                    minLiberty = liberty;
                    bestMoves.length = 0; // Empty the array
                }
                if (liberty == minLiberty) bestMoves.push([nextX, nextY]);
            }
            if (Math.random() >= 0.5) bestMoves.reverse();
            return bestMoves;
        }
        solve(x, y, moveCount=0) {
            this.grid[x][y] = moveCount++;
            if (moveCount == this.size * this.size) return true;
            // Try all of the BEST next moves from the current coordinate x, y
            for (let [nextX, nextY] of this.getBestMoveList(x, y)) {
                if (this.solve(nextX, nextY, moveCount)) return true;
            }
            console.log("backtrack");
            this.grid[x][y] = -1;
            return false;
        }
    }    
    
    // Driver code
    const solver = new Solver(8);
    let success = solver.solve(0, 0);
    console.log(success ? solver.toString() : "Solution does not exist");

    【讨论】:

    • 感谢您冗长而清晰的回答。
    猜你喜欢
    • 2013-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多