骑士之旅蛮力
Knight's Tour Brute Force
我不知道骑士是如何使用递归回溯的。我已经尝试了多种方法,你可以看到它已经注释掉了一些尝试,但它如何知道要回溯多远才能再次开始前进?我对递归的理解是,函数每次都使用新参数构建堆栈框架来调用自身,当它到达基本情况时,它会返回堆栈框架,在这种情况下向后移动。有人能指出我正确的方向吗?谢谢
#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;
int GAMEBOARD[8][8] = { 0 };
int TOTAL_MOVES = 0, BAD_MOVES = 0;
bool moveKnight(int row, int col, int movNum);
void print();
int main()
{
int startRow = 3, startCol = 3;
int moveNum = 1;
GAMEBOARD[startRow][startCol] = moveNum;
TOTAL_MOVES++;
moveKnight(startRow, startCol, moveNum);
if (moveKnight(startRow, startCol, moveNum) == true) {
cout << "Knight's Tour Solved! It took " << TOTAL_MOVES <<
" total moves and " << BAD_MOVES << " bad moves." << endl;
}
system("pause");
return 0;
}
bool moveKnight(int row, int col, int moveNum)
{
GAMEBOARD[row][col] = moveNum;
TOTAL_MOVES++;
if (moveNum == 64) {
return true;
}
if (GAMEBOARD[row][col] != 0) {
GAMEBOARD[row][col] = 0;
print();
system("pause");
return moveKnight(row, col, moveNum);
}
// commented out
/*if (GAMEBOARD[row - 2][col + 1] != 0) {
print();
system("pause");
return moveKnight(row - 2, col + 1, moveNum + 1);
}
else if (GAMEBOARD[row - 1][col + 2] != 0) {
print();
system("pause");
return moveKnight(row - 1, col + 2, moveNum + 1);
}
else if (GAMEBOARD[row + 1][col + 2] != 0) {
print();
system("pause");
return moveKnight(row + 1, col + 2, moveNum + 1);
}
else if (GAMEBOARD[row + 2][col + 1] != 0) {
print();
system("pause");
return moveKnight(row + 2, col + 1, moveNum + 1);
}
else if (GAMEBOARD[row + 2][col - 1] != 0) {
print();
system("pause");
return moveKnight(row + 2, col - 1, moveNum + 1);
}
else if (GAMEBOARD[row + 1][col - 2] != 0) {
print();
system("pause");
return moveKnight(row + 1, col - 2, moveNum + 1);
}
else if (GAMEBOARD[row - 1][col - 2] != 0) {
print();
system("pause");
return moveKnight(row - 1, col - 2, moveNum + 1);
}
else if (GAMEBOARD[row - 2][col - 1] != 0) {
print();
system("pause");
return moveKnight(row - 2, col - 1, moveNum + 1);
}
return false;*/
else if (row - 2 >= 0 && row - 2 <= 7 && col + 1 >= 0
&& col + 1 <= 7 && GAMEBOARD[row - 2][col + 1] == 0) {
GAMEBOARD[row - 2][col + 1] = moveNum;
print();
system("pause");
return moveKnight(row - 2, col + 1, moveNum + 1);
}
else if (row - 1 >= 0 && row - 1 <= 7 && col + 2 >= 0
&& col + 2 <= 7 && GAMEBOARD[row - 1][col + 2] == 0) {
GAMEBOARD[row - 1][col + 2] = moveNum;
print();
system("pause");
return moveKnight(row - 1, col + 2, moveNum + 1);
}
else if (row + 1 >= 0 && row + 1 <= 7 && col + 2 >= 0
&& col + 2 <= 7 && GAMEBOARD[row + 1][col + 2] == 0) {
GAMEBOARD[row + 1][col + 2] = moveNum;
print();
system("pause");
return moveKnight(row + 1, col + 2, moveNum + 1);
}
else if (row + 2 >= 0 && row + 2 <= 7 && col + 1 >= 0
&& col + 1 <= 7 && GAMEBOARD[row + 2][col + 1] == 0) {
GAMEBOARD[row + 2][col + 1] = moveNum;
print();
system("pause");
return moveKnight(row + 2, col + 1, moveNum + 1);
}
else if (row + 2 >= 0 && row + 2 <= 7 && col - 1 >= 0
&& col - 1 <= 7 && GAMEBOARD[row + 2][col - 1] == 0) {
GAMEBOARD[row + 2][col - 1] = moveNum;
print();
system("pause");
return moveKnight(row + 2, col - 1, moveNum + 1);
}
else if (row + 1 >= 0 && row + 1 <= 7 && col - 2 >= 0
&& col - 2 <= 7 && GAMEBOARD[row + 1][col - 2] == 0) {
GAMEBOARD[row + 1][col - 2] = moveNum;
print();
system("pause");
return moveKnight(row + 1, col - 2, moveNum + 1);
}
else if (row - 1 >= 0 && row - 1 <= 7 && col - 2 >= 0
&& col - 2 <= 7 && GAMEBOARD[row - 1][col - 2] == 0) {
GAMEBOARD[row - 1][col - 2] = moveNum;
print();
system("pause");
return moveKnight(row - 1, col - 2, moveNum + 1);
}
else if (row - 2 >= 0 && row - 2 <= 7 && col - 1 >= 0
&& col - 1 <= 7 && GAMEBOARD[row - 2][col - 1] == 0) {
GAMEBOARD[row - 2][col - 1] = moveNum;
print();
system("pause");
return moveKnight(row - 2, col - 1, moveNum + 1);
}
// commented out
/*if (row - 2 < 0 || row - 2 > 7 || col + 1 < 0
|| col + 1 > 7 || GAMEBOARD[row - 2][col + 1] != 0) {
GAMEBOARD[row - 2][col + 1] = 0;
return moveKnight(row - 2, col + 1, moveNum + 1);
}
else if (row - 1 < 0 || row - 1 > 7 || col + 2 < 0
|| col + 2 > 7 || GAMEBOARD[row - 1][col + 2] != 0) {
GAMEBOARD[row - 1][col + 2] = 0;
return moveKnight(row - 1, col + 2, moveNum + 1);
}
else if (row + 1 < 0 || row + 1 > 7 || col + 2 < 0
|| col + 2 > 7 || GAMEBOARD[row + 1][col + 2] != 0) {
GAMEBOARD[row + 1][col + 2] = 0;
moveKnight(row + 1, col + 2, moveNum + 1);
return false;
}
else if (row + 2 < 0 || row + 2 > 7 || col + 1 < 0
|| col + 1 > 7 || GAMEBOARD[row + 2][col + 1] != 0) {
GAMEBOARD[row + 2][col + 1] = 0;
moveKnight(row + 2, col + 1, moveNum + 1);
return false;
}
else if (row + 2 < 0 || row + 2 > 7 || col - 1 < 0
|| col - 1 > 7 || GAMEBOARD[row + 2][col - 1] != 0) {
GAMEBOARD[row + 2][col - 1] = 0;
moveKnight(row + 2, col - 1, moveNum + 1);
return false;
}
else if (row + 1 < 0 || row + 1 > 7 || col - 2 < 0
|| col - 2 > 7 || GAMEBOARD[row + 1][col - 2] != 0) {
GAMEBOARD[row + 1][col - 2] = 0;
moveKnight(row + 1, col - 2, moveNum + 1);
return false;
}
else if (row - 1 < 0 || row - 1 > 7 || col - 2 < 0
|| col - 2 > 7 || GAMEBOARD[row - 1][col - 2] != 0) {
GAMEBOARD[row - 1][col - 2] = 0;
moveKnight(row - 1, col - 2, moveNum + 1);
return false;
}
else if (row - 2 < 0 || row - 2 > 7 || col - 1 < 0
|| col - 1 > 7 || GAMEBOARD[row - 2][col - 1] != 0) {
GAMEBOARD[row - 2][col - 1] = 0;
moveKnight(row - 2, col - 1, moveNum + 1);
return false;
}
*/
cout << endl << endl;
return false;
}
void print()
{
for (int row = 0; row <= 7; row++) {
for (int col = 0; col <= 7; col++) {
cout << setw(5) << GAMEBOARD[row][col];
}
cout << endl;
}
}
递归可能很难掌握!
我强烈建议您在尝试开始编写代码之前尝试考虑您的算法将如何工作。
首先明确定义您的基本案例。你做得很好。我们有:
if (moveNum == 64) {
return true;
}
现在,我们需要考虑如何从每个位置处理马的 8 种可能移动。我将使用一些 sudo 代码为此简化您的代码:
moves = [[2, 1], [2, 1], [-2, -1], etc...]; // 8 moves total
for (move : moves) {
newRow = row + move[0];
newCol = col + move[1];
if (InBounds(newRow, newCol) && GAMEBOARD[newRow][newCol] == 0) {
// Backtracking logic goes here
}
}
此代码基本上与您的 if 语句执行相同的操作,但更易于使用和概念化。
递归回溯基本上有两个步骤。首先,我们检查是否达到了基本情况。第二,我们处理追溯案件。使用递归回溯,这包括几个步骤:
- 做点什么(在这种情况下,移动骑士)
- 进行递归调用以检查这是否会产生解决方案
- 如果这产生了解决方案,请告诉此函数的调用者我们找到了解决方案。此外,您可能想对找到的解决方案做些事情。
- 这没有产生解决方案。撤消我们在第一步中所做的,并查看其他递归情况是否导致解决方案
- 如果没有递归情况导致找到解决方案,则告诉调用者从当前位置无法找到解决方案。
将此格式应用于骑士之旅:
- 在棋盘上走一步:
GAMEBOARD[newRow][newCol] = moveNum
- 测试此移动是否导致解决方案:
result = moveKnight(newRow, newCol, moveNum + 1)
- 如果我们找到了解决方案,暂时 return 正确。
if (result) {return true;}
- 如果此步无效,请撤消我们所做的步:
GAMEBOARD[newRow][newCol] = 0
。然后,我们应该看看其他递归情况是否有解决方案。我的代码通过遍历每个动作来处理这个问题。您通过执行一系列 if/else 语句来处理它。
- 此语句中没有导致解决方案的移动。我们应该
return false
来表明这一点。
将所有这些放在一起,我们得到:
bool moveKnight(int row, int col, int moveNum) {
if (moveNum == 64) {
return true;
}
moves = [[2, 1], [2, 1], [-2, -1], etc...]; // 8 moves total
for (move : moves) {
int newRow = row + move[0];
int newCol = col + move[1];
if (InBounds(newRow, newCol) && GAMEBOARD[newRow][newCol] == 0) {
GAMEBOARD[newRow][newCol] = moveNum;
bool result = moveKnight(newRow, newCol, moveNum + 1);
if (result) {
return true;
} else {
// Undo this move
GAMEBOARD[newRow][newCol] = 0;
}
}
}
return false;
}
因为我们在找到正确的解决方案后不会撤消移动,所以当 moveKnight
return 为真时,GAMEBOARD 将包含一个解决方案。
我不知道骑士是如何使用递归回溯的。我已经尝试了多种方法,你可以看到它已经注释掉了一些尝试,但它如何知道要回溯多远才能再次开始前进?我对递归的理解是,函数每次都使用新参数构建堆栈框架来调用自身,当它到达基本情况时,它会返回堆栈框架,在这种情况下向后移动。有人能指出我正确的方向吗?谢谢
#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;
int GAMEBOARD[8][8] = { 0 };
int TOTAL_MOVES = 0, BAD_MOVES = 0;
bool moveKnight(int row, int col, int movNum);
void print();
int main()
{
int startRow = 3, startCol = 3;
int moveNum = 1;
GAMEBOARD[startRow][startCol] = moveNum;
TOTAL_MOVES++;
moveKnight(startRow, startCol, moveNum);
if (moveKnight(startRow, startCol, moveNum) == true) {
cout << "Knight's Tour Solved! It took " << TOTAL_MOVES <<
" total moves and " << BAD_MOVES << " bad moves." << endl;
}
system("pause");
return 0;
}
bool moveKnight(int row, int col, int moveNum)
{
GAMEBOARD[row][col] = moveNum;
TOTAL_MOVES++;
if (moveNum == 64) {
return true;
}
if (GAMEBOARD[row][col] != 0) {
GAMEBOARD[row][col] = 0;
print();
system("pause");
return moveKnight(row, col, moveNum);
}
// commented out
/*if (GAMEBOARD[row - 2][col + 1] != 0) {
print();
system("pause");
return moveKnight(row - 2, col + 1, moveNum + 1);
}
else if (GAMEBOARD[row - 1][col + 2] != 0) {
print();
system("pause");
return moveKnight(row - 1, col + 2, moveNum + 1);
}
else if (GAMEBOARD[row + 1][col + 2] != 0) {
print();
system("pause");
return moveKnight(row + 1, col + 2, moveNum + 1);
}
else if (GAMEBOARD[row + 2][col + 1] != 0) {
print();
system("pause");
return moveKnight(row + 2, col + 1, moveNum + 1);
}
else if (GAMEBOARD[row + 2][col - 1] != 0) {
print();
system("pause");
return moveKnight(row + 2, col - 1, moveNum + 1);
}
else if (GAMEBOARD[row + 1][col - 2] != 0) {
print();
system("pause");
return moveKnight(row + 1, col - 2, moveNum + 1);
}
else if (GAMEBOARD[row - 1][col - 2] != 0) {
print();
system("pause");
return moveKnight(row - 1, col - 2, moveNum + 1);
}
else if (GAMEBOARD[row - 2][col - 1] != 0) {
print();
system("pause");
return moveKnight(row - 2, col - 1, moveNum + 1);
}
return false;*/
else if (row - 2 >= 0 && row - 2 <= 7 && col + 1 >= 0
&& col + 1 <= 7 && GAMEBOARD[row - 2][col + 1] == 0) {
GAMEBOARD[row - 2][col + 1] = moveNum;
print();
system("pause");
return moveKnight(row - 2, col + 1, moveNum + 1);
}
else if (row - 1 >= 0 && row - 1 <= 7 && col + 2 >= 0
&& col + 2 <= 7 && GAMEBOARD[row - 1][col + 2] == 0) {
GAMEBOARD[row - 1][col + 2] = moveNum;
print();
system("pause");
return moveKnight(row - 1, col + 2, moveNum + 1);
}
else if (row + 1 >= 0 && row + 1 <= 7 && col + 2 >= 0
&& col + 2 <= 7 && GAMEBOARD[row + 1][col + 2] == 0) {
GAMEBOARD[row + 1][col + 2] = moveNum;
print();
system("pause");
return moveKnight(row + 1, col + 2, moveNum + 1);
}
else if (row + 2 >= 0 && row + 2 <= 7 && col + 1 >= 0
&& col + 1 <= 7 && GAMEBOARD[row + 2][col + 1] == 0) {
GAMEBOARD[row + 2][col + 1] = moveNum;
print();
system("pause");
return moveKnight(row + 2, col + 1, moveNum + 1);
}
else if (row + 2 >= 0 && row + 2 <= 7 && col - 1 >= 0
&& col - 1 <= 7 && GAMEBOARD[row + 2][col - 1] == 0) {
GAMEBOARD[row + 2][col - 1] = moveNum;
print();
system("pause");
return moveKnight(row + 2, col - 1, moveNum + 1);
}
else if (row + 1 >= 0 && row + 1 <= 7 && col - 2 >= 0
&& col - 2 <= 7 && GAMEBOARD[row + 1][col - 2] == 0) {
GAMEBOARD[row + 1][col - 2] = moveNum;
print();
system("pause");
return moveKnight(row + 1, col - 2, moveNum + 1);
}
else if (row - 1 >= 0 && row - 1 <= 7 && col - 2 >= 0
&& col - 2 <= 7 && GAMEBOARD[row - 1][col - 2] == 0) {
GAMEBOARD[row - 1][col - 2] = moveNum;
print();
system("pause");
return moveKnight(row - 1, col - 2, moveNum + 1);
}
else if (row - 2 >= 0 && row - 2 <= 7 && col - 1 >= 0
&& col - 1 <= 7 && GAMEBOARD[row - 2][col - 1] == 0) {
GAMEBOARD[row - 2][col - 1] = moveNum;
print();
system("pause");
return moveKnight(row - 2, col - 1, moveNum + 1);
}
// commented out
/*if (row - 2 < 0 || row - 2 > 7 || col + 1 < 0
|| col + 1 > 7 || GAMEBOARD[row - 2][col + 1] != 0) {
GAMEBOARD[row - 2][col + 1] = 0;
return moveKnight(row - 2, col + 1, moveNum + 1);
}
else if (row - 1 < 0 || row - 1 > 7 || col + 2 < 0
|| col + 2 > 7 || GAMEBOARD[row - 1][col + 2] != 0) {
GAMEBOARD[row - 1][col + 2] = 0;
return moveKnight(row - 1, col + 2, moveNum + 1);
}
else if (row + 1 < 0 || row + 1 > 7 || col + 2 < 0
|| col + 2 > 7 || GAMEBOARD[row + 1][col + 2] != 0) {
GAMEBOARD[row + 1][col + 2] = 0;
moveKnight(row + 1, col + 2, moveNum + 1);
return false;
}
else if (row + 2 < 0 || row + 2 > 7 || col + 1 < 0
|| col + 1 > 7 || GAMEBOARD[row + 2][col + 1] != 0) {
GAMEBOARD[row + 2][col + 1] = 0;
moveKnight(row + 2, col + 1, moveNum + 1);
return false;
}
else if (row + 2 < 0 || row + 2 > 7 || col - 1 < 0
|| col - 1 > 7 || GAMEBOARD[row + 2][col - 1] != 0) {
GAMEBOARD[row + 2][col - 1] = 0;
moveKnight(row + 2, col - 1, moveNum + 1);
return false;
}
else if (row + 1 < 0 || row + 1 > 7 || col - 2 < 0
|| col - 2 > 7 || GAMEBOARD[row + 1][col - 2] != 0) {
GAMEBOARD[row + 1][col - 2] = 0;
moveKnight(row + 1, col - 2, moveNum + 1);
return false;
}
else if (row - 1 < 0 || row - 1 > 7 || col - 2 < 0
|| col - 2 > 7 || GAMEBOARD[row - 1][col - 2] != 0) {
GAMEBOARD[row - 1][col - 2] = 0;
moveKnight(row - 1, col - 2, moveNum + 1);
return false;
}
else if (row - 2 < 0 || row - 2 > 7 || col - 1 < 0
|| col - 1 > 7 || GAMEBOARD[row - 2][col - 1] != 0) {
GAMEBOARD[row - 2][col - 1] = 0;
moveKnight(row - 2, col - 1, moveNum + 1);
return false;
}
*/
cout << endl << endl;
return false;
}
void print()
{
for (int row = 0; row <= 7; row++) {
for (int col = 0; col <= 7; col++) {
cout << setw(5) << GAMEBOARD[row][col];
}
cout << endl;
}
}
递归可能很难掌握! 我强烈建议您在尝试开始编写代码之前尝试考虑您的算法将如何工作。
首先明确定义您的基本案例。你做得很好。我们有:
if (moveNum == 64) {
return true;
}
现在,我们需要考虑如何从每个位置处理马的 8 种可能移动。我将使用一些 sudo 代码为此简化您的代码:
moves = [[2, 1], [2, 1], [-2, -1], etc...]; // 8 moves total
for (move : moves) {
newRow = row + move[0];
newCol = col + move[1];
if (InBounds(newRow, newCol) && GAMEBOARD[newRow][newCol] == 0) {
// Backtracking logic goes here
}
}
此代码基本上与您的 if 语句执行相同的操作,但更易于使用和概念化。
递归回溯基本上有两个步骤。首先,我们检查是否达到了基本情况。第二,我们处理追溯案件。使用递归回溯,这包括几个步骤:
- 做点什么(在这种情况下,移动骑士)
- 进行递归调用以检查这是否会产生解决方案
- 如果这产生了解决方案,请告诉此函数的调用者我们找到了解决方案。此外,您可能想对找到的解决方案做些事情。
- 这没有产生解决方案。撤消我们在第一步中所做的,并查看其他递归情况是否导致解决方案
- 如果没有递归情况导致找到解决方案,则告诉调用者从当前位置无法找到解决方案。
将此格式应用于骑士之旅:
- 在棋盘上走一步:
GAMEBOARD[newRow][newCol] = moveNum
- 测试此移动是否导致解决方案:
result = moveKnight(newRow, newCol, moveNum + 1)
- 如果我们找到了解决方案,暂时 return 正确。
if (result) {return true;}
- 如果此步无效,请撤消我们所做的步:
GAMEBOARD[newRow][newCol] = 0
。然后,我们应该看看其他递归情况是否有解决方案。我的代码通过遍历每个动作来处理这个问题。您通过执行一系列 if/else 语句来处理它。 - 此语句中没有导致解决方案的移动。我们应该
return false
来表明这一点。
将所有这些放在一起,我们得到:
bool moveKnight(int row, int col, int moveNum) {
if (moveNum == 64) {
return true;
}
moves = [[2, 1], [2, 1], [-2, -1], etc...]; // 8 moves total
for (move : moves) {
int newRow = row + move[0];
int newCol = col + move[1];
if (InBounds(newRow, newCol) && GAMEBOARD[newRow][newCol] == 0) {
GAMEBOARD[newRow][newCol] = moveNum;
bool result = moveKnight(newRow, newCol, moveNum + 1);
if (result) {
return true;
} else {
// Undo this move
GAMEBOARD[newRow][newCol] = 0;
}
}
}
return false;
}
因为我们在找到正确的解决方案后不会撤消移动,所以当 moveKnight
return 为真时,GAMEBOARD 将包含一个解决方案。