我使用递归回溯的国际象棋骑士之旅代码不起作用。
#include <iostream>
using namespace std;
// goal: knight tour
#define N 8
void printArray(int board[N][N])
{
for(int i = 0; i < N; i ++)
{
for(int j = 0; j < N; j ++)
{
cout << board[i][j] << " ";
}
cout << endl;
}
}
void instArray(int board[N][N])
{
for(int i = 0; i < N; i ++)
for(int j = 0; j < N; j ++)
board[i][j] = 0;
board[0][0] = 1;
}
bool isValidMove(int posX, int posY, int moveX, int moveY, int board[N][N])
{
int finalX = posX + moveX;
int finalY = posY + moveY;
if(finalX < 0 ||
finalX > 7 ||
finalY < 0 ||
finalY > 7 ||
board[finalY][finalX] != 0)
return false;
return true;
}
bool solveKnightTour(int board[N][N], int n, int posX, int posY, int
moveX[N], int moveY[N])
{
int next_x, next_y;
if(n == 65) return true;//when n is equal to 62 the code compiles
for(int i = 0; i < 8; i ++)
{
if(isValidMove(posX, posY, moveX[i], moveY[i], board))
{
next_x = posX + moveX[i];
next_y = posY + moveY[i];
board[next_y][next_x] = n;
if(solveKnightTour(board, n + 1, next_x, next_y, moveX, moveY))
return true;
else board[next_y][next_x] = 0;
}
}
return false;
}
int main()
{
int board[N][N];
int moveX[8] = {1, 1, 2, 2, -1, -1, -2, -2};
int moveY[8] = {2, -2, 1, -1, 2, -2, 1, -1};
instArray(board);
solveKnightTour(board, 2, 0, 0, moveX, moveY);
printArray(board);
}
没有错误,但是代码似乎无限循环。 在solveKnightTour函数中,当n等于62时,代码将用印制板编译,但是结果不能完全解决骑士巡回赛。
答案 0 :(得分:1)
由于moveX
和moveY
数组的排序非常对称,因此您的程序需要很长时间才能找到解决方案。如果将组合按此顺序放置,则会以循环方式遍历方向:
int moveX[8] = {1, 2, 2, 1, -1, -2, -2, -1};
int moveY[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
程序将几乎立即找到解决方案。
在您的代码中,首先搜索“上2向右1”,然后搜索“下2向右1”,然后骑士将沿棋盘顶部曲折,从a8到b6到c8到d6等。沿着板顶部无法访问,程序浪费时间搜索所有这些肯定会失败的组合。
递归回溯是一种效率低下的算法,因为它可以播放大量的组合,因此最初在此处无法使用。 4x4或5x5电路板不会出现这些问题,因为它呈指数级扩展。但是在这种情况下,我提供的答案只能“恰好”起作用。通常,强行使用这种规模的东西往往比您有时间需要更多的计算。
经过编辑以概括/修改答案