【问题标题】:Knight's Tour backtracking infinite loop骑士之旅回溯无限循环
【发布时间】:2013-08-07 01:13:44
【问题描述】:

我正在尝试为the Knight's Tour 编写代码:

一个骑士的旅行是一个骑士在棋盘上的一系列移动,使得骑士恰好访问每个方格一次。

我一直在尝试更改其他人的代码,但回溯似乎无法正常工作 - 它永远找不到解决方案。当骑士从 0、0 开始时它工作得非常好,但如果它从 2D 网格上的任何其他位置开始,程序就会永远继续下去。

这段代码的错误在哪里?

#include <iostream>
#include <ctime>
using namespace std;

const int N = 8;
int map[N][N];

/* A utility function to check if i,j are valid indexes for N*N chessboard */
bool isSafe(int x, int y) {
    return x >= 0 && x < N && y >= 0 && y < N && map[x][y] == -1;
}

/* A utility function to print solution matrix sol[N][N] */
void printSolution() {
    for (int x = 0; x < N; x++) {
        for (int y = 0; y < N; y++)
            cout << map[x][y];
        cout << endl;
    }
}

/* A recursive utility function to solve Knight Tour problem */
bool knightsTourRecursive(int x, int y, int movei, int xMove[N], int yMove[N]) {
    int nextX, nextY;

    if (movei == N*N)
        return true;

    /* Try all next moves from the current coordinate x, y */
    for (int k = 0; k < 8; k++) {
        nextX = x + xMove[k];
        nextY = y + yMove[k];

        if (isSafe(nextX, nextY)) {
            map[nextX][nextY] = movei;

            if (knightsTourRecursive(nextX, nextY, movei+1, xMove, yMove))  // recursion
                return true;
            else
                map[nextX][nextY] = -1;             // backtracking
        }
    }
    return false;
}

bool knightsTour() {
    /* Initialization of solution matrix */
    for (int x = 0; x < N; x++)
        for (int y = 0; y < N; y++)
            map[x][y] = -1;

    /* xMove[] and yMove[] define next move of Knight.
       xMove[] is for next value of x coordinate
       yMove[] is for next value of y coordinate */
    int xMove[8] = {  2, 1, -1, -2, -2, -1,  1,  2 };
    int yMove[8] = {  1, 2,  2,  1, -1, -2, -2, -1 };

    int initX = rand() % N;
    int initY = rand() % N;

    cout << "Starting at " << initX << " " << initY << endl;

    // Since the Knight is initially at the first block
    map[initX][initY]  = 0;

    /* explore all tours using solveKTUtil() */
    if(!knightsTourRecursive(initX, initY, 1, xMove, yMove) ) {
        cout << "Solution does not exist" << endl;
        return false;
    }
    else
        printSolution();

    return true;
}

int main() {
    srand( (unsigned) time(0));
    knightsTour();

    cin.get();
    return 0;
}

【问题讨论】:

  • 你确定它真的会永远持续下去吗?它可能非常非常非常慢。顺便说一句,从逻辑上讲,knightsTourRecursive 声明中的xMoveyMove 参数的大小是8 而不是N(也就是说,骑士可以移动的数量,而不是棋盘的大小。 )
  • 是的,没错,您应该将参数更改为 xMove[8] 和 yMove[8]。骑士可以做 8 种可能的移动,这与棋盘大小无关。在当前代码中,如果您将棋盘大小更改为更小的棋盘(例如 N=4),那么马将无法执行所有可能的动作,您将永远不会得到结果。

标签: c++ algorithm recursion backtracking knights-tour


【解决方案1】:

这个程序似乎完全正确,我看不出这段代码有错误。

然而,骑士之旅是一个高度复杂的算法。实际上,程序需要通过板子检查多达 64!=1*2*3*...*64 种不同的方式。这是一个有 89 个零的数字!

在许多情况下,回溯会在早期的分支处停止,但有些分支会永远上升。

如果从 0,0 开始的游览如此快速地找到,那么这可能是纯粹的机会,或者数组 xMove 和 yMove 被巧妙地初始化,从而快速找到 (0,0) 的解决方案。

所以问题不是你的程序,而是算法。我建议你对这个主题做一些研究。骑士之旅有很多算法,可以在更合理的时间内为您提供解决方案。

【讨论】:

  • 谢谢!您能为骑士之旅提出一个更好的解决方案吗?
  • 使用这个启发式:选择导致选择数量最少的移动 (Warnsdorff's Rule)。
【解决方案2】:

我没有足够的声誉来发表评论,但这更像是评论。检查here 以获取Warnsdorff's Rule 的python 实现。讨论了对 Warnsdorff 规则的进一步优化here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    • 1970-01-01
    相关资源
    最近更新 更多