问题描述
假设国际象棋盘有5*5共有25个格子。设计一个程序,使棋子从初始位置(棋盘格编号为1的位置)开始跳马,能够把棋盘的格子全部走一遍,每个格子只允许走一次。要求:1)输出一个解(用二维数组来记录跳马的过程,即[步号,棋盘编号],左上角为1步起点;2)求总共有多少解?*注:国际象棋的棋子是在格子中间的。国际象棋中的“马走日”,如下图所示,第一步为[1,1],第二步为[2,8]或者[2,12],第三步可以是[3,5]或[3,21],等,依次类推。
#include <cstdio>
const int n = 5;
int vis[n][n];
int path[n*n];
int dr[] = {-2, -1, 1, 2, 2, 1, -1, -2}; // 方向数组
int dc[] = {1, 2, 2, 1, -1, -2, -2, -1};
int cnt = 0; // 记录总共有多少种方案
void dfs(int r, int c, int step) {
if(step==n*n) { // 搜索完前部结点
cnt++; // 方案数加一
if(cnt==1) { // 只打印第一个中方案
for(int i=0; i<n*n; i++) {
printf("[%d,%d]\n", i+1, path[i]);
}
}
} else {
for(int i=0; i<8; i++) { // 尝试八个方向的邻居结点
int newr = r + dr[i]; // 邻居结点
int newc = c + dc[i];
if( 0<=newr && newr<n && 0<=newc && newc<n && vis[newr][newc]==0) {
path[step] = newr * n + newc + 1; // 当前结点的编号加入搜索路径
vis[newr][newc]=1; // 标记访问
dfs(newr, newc, step+1);
vis[newr][newc]=0; // 回溯后修改状态
}
}
}
}
int main() {
path[0] = 1; // 将第一个结点加入路径中
vis[0][0] = 1; // 标记第一个结点为访问过
dfs(0, 0, 1); // 开始dfs遍历
printf("%d", cnt);
return 0;
}