【题目来自灰灰考研】
(2018上海交通大学上机题)(2017华中科技大学上机题)
假设国际象棋棋盘有5*5共25个格子。设计一个程序,使棋子从初始位置(如图)开始跳马,需要将棋盘的格子全部都走一遍,每个格子只允许走一次。
问:总共有多少解。(提示:回溯法)
P.S国际象棋的棋子是在格子中间的。国际象棋中的“马走日”,如下图2所示,第一步为[1,1],第二步为[2,8]或[2,12],第三步可以是[3,5]或[3,21]等,以此类推。
#include<iostream>
#include<cstdlib>
#include<cstring>
#define MIN 0xc0c0c0c0
#define MAX 0x3f3f3f3f
using namespace std;
const int n = 5, m = 5;//定义问题规模
int count = 0;//问题解法数量
int map[n][m], trace[5][5], visit[5][5];//map表示整个地图,trace记录路径,visit用来记录当前点是否被走过
int moveDirection[][2] = {1, 2, 1, -2, -1, 2, -1, -2, 2, 1, 2, -1, -2, 1, -2, -1};//下一步相对于当前位置的偏移量
void PrintTrace(int data[][m]);
void HorseJumpSolutionNumbers(int x, int y, int steps)
{
trace[x][y] = steps;
if(n * m == steps)//如果走的步数等于问题的规模,即找到一种解法
{
if(count == 0)
PrintTrace(trace);//这路仅仅打印第一个解法的路径
count++;//问题解法+ 1
}
int nextX, nextY;
for(int i = 0; i < 8; i++)
{
nextX = x + moveDirection[i][0];
nextY = y + moveDirection[i][1];//下一步的坐标
if(nextX < 0 || nextX >= n || nextY < 0 || nextY >= m)//判断坐标是否合法
continue;
if(visit[nextX][nextY] == 0)//坐标合法且未被访问过,才进行访问
{
visit[nextX][nextY] = 1;//访问标记为1
HorseJumpSolutionNumbers(nextX, nextY, steps + 1);//以当前点为父节点,递归访问下一步
visit[nextX][nextY] = 0;//以当前点为基准访问完所有子问题的解空间后,要进行回溯,所以要取消当前节点的标记
}
}
}
void PrintTrace(int data[][m])
{
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
cout<<trace[i][j]<<"\t";
}
cout<<endl;
}
cout<<"==================="<<endl;
}
int main()
{
int x, y;
memset(map, 0, sizeof(map));
memset(trace, 0, sizeof(trace));
memset(visit, 0, sizeof(visit));
x = 0;
y = 0;
visit[x][y] = 1;
HorseJumpSolutionNumbers(x, y, 1);
cout<<"共有走法:"<<count<<endl;
return 0;
}