骑士巡游问题
Posted southerneast
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了骑士巡游问题相关的知识,希望对你有一定的参考价值。
问题概述
骑士巡游问题对国际象棋爱好者来说是较有意思的难题之一。这个问题是:称为骑士的棋子在一个空的棋盘上行进,能否在64个方格棋盘上的每个方格都走一次且只走一次。
在国际象棋中,骑士的移动路线是L形的(在一个方向上走两格,在垂直方向上走一格)。因此在一个空棋盘中间的方格上,其实可以有8种不同的移动方式(从0到7编号),如下图所示:
可达性试探法
算法思想
根据每个方格的可到达程度将它们分类,然后总是把骑士移动到最难到达的那个方格(当然,要符合骑士的L形移动规则)。我们给一个二维array对象access填上数,这些数表示每个方格周围有多少个可到达的方格。在一个空棋盘上,每个中心方格定为8,每个角落定为2,其他的方格为3、4或6,如下所示:
在任何时候,骑士都应该移动到具有最低可达数的方格。如果满足此条件的方格不止一个,骑士可以选择移动到其中的任何一个方格。因此,骑士巡游可以从任何一个角落开始。需要注意的是:随着骑士在棋盘上的移动,越来越多的方格被占用,因此应该随之减少可达数。
这样,在巡游的任何时刻,每个有效方格的可达数与该方格可到达的确切方格数保持相等。
C++实现
#include <iostream>
#include <iomanip>
#include <ctime>
using namespace std;
const int SIZE = 8;
// 检测当前选择的位置是否有效
bool vaildWay(int col, int row, int board[][SIZE]) {
return (col >= 0 && col < SIZE && row >= 0
&& row < SIZE && !board[row][col]);
}
int main() {
int board[SIZE][SIZE] = { 0 }; // 初始化棋盘数组
int access[SIZE][SIZE] = { 2, 3, 4, 4, 4, 4, 3, 2,
3, 4, 6, 6, 6, 6, 4, 3,
4, 6, 8, 8, 8, 8, 6, 4,
4, 6, 8, 8, 8, 8, 6, 4,
4, 6, 8, 8, 8, 8, 6, 4,
4, 6, 8, 8, 8, 8, 6, 4,
3, 4, 6, 6, 6, 6, 4, 3,
2, 3, 4, 4, 4, 4, 3, 2 }; // 可达性数组
int horizontal[SIZE] = { 2, 1, -1, -2, -2, -1, 1, 2 }; // 水平位移
int vertical[SIZE] = { -1, -2, -2, -1, 1, 2, 2, 1 }; // 垂直位移
int currentCol, currentRow; // 当前位置
int testCol, testRow; // 测试位置
int moveSteps = 0; // 移动步伐
srand(time(0));
currentCol = rand() % 8; // 随机选择起始位置
currentRow = rand() % 8;
board[currentRow][currentCol] = ++moveSteps; // 标记起始位置
bool done = false;
while (!done) {
int miniWay = 9; // 挑选最小的可达性位置
int direction = -1; // 记录方向
for (int i = 0; i < SIZE; ++i) { // 扫描8个方向
testCol = currentCol + horizontal[i];
testRow = currentRow + vertical[i];
if (vaildWay(testCol, testRow, board)) {
if (access[testRow][testCol] < miniWay) {
miniWay = access[testRow][testCol];
direction = i;
}
--access[testRow][testCol]; // 更新可达性数组
}
}
if (direction == -1) // 如果没有合适的方向
done = true;
else { // 更新当前位置
currentCol += horizontal[direction];
currentRow += vertical[direction];
board[currentRow][currentCol] = ++moveSteps;
}
}
if (moveSteps == 64) // 如果遍历到所有的方格位置
cout << " successful!!
";
else
cout << " failed
";
for (int i = 0; i < SIZE; ++i) { // 输出棋盘数据
for (int j = 0; j < SIZE; ++j)
cout << setw(4) << board[i][j];
cout << endl;
}
return 0;
}
以上是关于骑士巡游问题的主要内容,如果未能解决你的问题,请参考以下文章
骑士巡游的问题简述如下:在国际象棋盘上某一位置放置一个马的棋子,然后采用象棋中“马走日字”规则