C++递归实现马踏棋盘算法详解
马踏棋盘即骑士周游问题,要求一枚棋子在不重复经过任何一格的前提下遍历整个棋盘。本文基于C++语言,采用递归与回溯策略,详细解析如何通过状态探索寻找可行路径,并附带完整代码示例供参考。
问题原理与思路
马踏棋盘是经典的组合数学问题。假设棋盘大小为 X × Y,我们需要找到一条长度为 X * Y 的路径,使得马按照“日”字形移动规律覆盖所有格子。
算法的核心逻辑如下:
- 状态记录:使用二维数组
chess[Y][X]标记当前格子的访问序号,未访问为0。 - 试探方向:定义8个可能的跳跃方向,通常按顺时针排列,依次尝试。
- 递归回溯:
- 若当前点有合法下一步,标记步数并递归进入下一层;
- 若递归返回失败或无路可走,则撤销当前步标记(置0),尝试下一个方向;
- 当已覆盖总格子数时,说明找到解。
代码实现解析
以下代码实现了一个5x5的棋盘测试案例。主要包含三个部分:方向判定、递归探索结果输出。
第1步:定义方向判定函数 Next
该函数根据给定的8个方向索引,计算偏移量并检查目标位置是否在棋盘内且未被访问。若符合条件,则更新坐标指针并返回1,否则返回0。
第2步:执行递归探索 Explore
这是核心算法。counter 记录当前步数,chess[y][x] 记录路径。函数尝试每个方向,如果找到一个有效位置,就递归调用自身。如果递归返回假,或者所有方向都无效,则执行回溯操作:将当前格子复位为0,步数减1,并尝试其他方向。
第3步:输出结果与计时 ShowResult & main
初始化起始点后调用探索函数。成功找到路径后,遍历数组打印出每格的访问顺序。同时使用 clock() 记录算法耗时。
#include<iostream>
#include<time.h>
using namespace std;
#define X 5
#define Y 5
int chess[Y][X] = {0};
int counter = 0;
// 寻找下一跳的方向
int Next(int* x, int* y, int where) {
switch(where) {
case 0:
if(*x+1<X && *y-2>=0 && chess[*y-2][*x+1]==0) {
*x+=1; *y-=2; return 1;
}
break;
case 1:
if(*x+2<X && *y-1>=0 && chess[*y-1][*x+2]==0) {
*x+=2; *y-=1; return 1;
}
break;
case 2:
if(*x+2<X && *y+1<Y && chess[*y+1][*x+2]==0) {
*x+=2; *y+=1; return 1;
}
break;
case 3:
if(*x+1<X && *y+2<Y && chess[*y+2][*x+1]==0) {
*x+=1; *y+=2; return 1;
}
break;
case 4:
if(*x-1>=0 && *y+2<Y && chess[*y+2][*x-1]==0) {
*x-=1; *y+=2; return 1;
}
break;
case 5:
if(*x-2>=0 && *y+1<Y && chess[*y+1][*x-2]==0) {
*x-=2; *y+=1; return 1;
}
break;
case 6:
if(*x-2>=0 && *y-1>=0 && chess[*y-1][*x-2]==0) {
*x-=2; *y-=1; return 1;
}
break;
case 7:
if(*x-1>=0 && *y-2>=0 && chess[*y-2][*x-1]==0) {
*x-=1; *y-=2; return 1;
}
break;
}
return 0;
}
// 递归回溯探索
int Explore(int x, int y) {
int x1=x, y1=y;
int flag, where=0;
counter++;
chess[y][x] = counter;
// 如果已经走遍全图,返回成功
if(counter == X * Y) {
return 1;
}
// 尝试第一个方向
flag = Next(&x1, &y1, where);
while(flag==0 && where<7) {
where++;
flag = Next(&x1, &y1, where);
}
// 只要有路可选,就继续深入或回溯
while(flag) {
if(Explore(x1, y1)==1) {
return 1;
} else {
// 此路不通,回溯
x1=x; y1=y;
where++;
flag = Next(&x1, &y1, where);
while(flag==0 && where<7) {
where++;
flag = Next(&x1, &y1, where);
}
}
}
// 彻底无路可走,回溯到上一层
if(flag==0) {
chess[y][x] = 0;
counter--;
}
return 0;
}
void ShowResult() {
for(int i=0; i<Y; i++) {
for(int j=0; j<X; j++) {
cout.width(4);
cout << chess[i][j] << ' ';
}
cout << endl;
}
cout << endl;
}
int main() {
int start = clock();
// 从 (2, 1) 开始尝试
int result = Explore(2, 1);
int end = clock();
if(result) {
ShowResult();
} else {
cout << "have no path!" << endl;
}
cout << "spend time: " << (end-start)/CLOCKS_PER_SEC << " s" << endl;
return 0;
}
总结
马踏棋盘问题通过简单的回溯算法即可解决,但在较大棋盘上复杂度会呈指数级增长,因此对于8x8甚至更大规模的棋盘,通常需要引入启发式算法优化。以上就是C++实现马踏棋盘的详细内容,更多关于骑士周游算法的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













