题目描述
Knight Moves
Problem Description
A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.
Of course you know that it is vice versa. So you offer him to write a program that solves the “difficult” part.
Your job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b.
Input
The input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard.
Output
For each test case, print one line saying “To get from xx to yy takes n knight moves.”.
Sample Input
e2 e4 a1 b2 b2 c3 a1 h8 a1 h7 h8 a1 b1 c3 f6 f6
Sample Output
To get from e2 to e4 takes 2 knight moves. To get from a1 to b2 takes 4 knight moves. To get from b2 to c3 takes 2 knight moves. To get from a1 to h8 takes 6 knight moves. To get from a1 to h7 takes 5 knight moves. To get from h8 to a1 takes 6 knight moves. To get from b1 to c3 takes 1 knight moves. To get from f6 to f6 takes 0 knight moves.
对于这道题,我需要普及一个只知识点国际象棋走法,可以走8个方向
那么现在切入正题,对于广度优先搜索,我们用到了队列。
我们从起始点开始走,分别走到八个方向上并在每个方向上判断是否已到达终点。如到达,直接输出步数,否则,入队列。
在每判断一点时,该点都要出队列,且每一判断的点,都是位于队首的点。
我们先来看一下实现深搜的代码
//这是伪码
int x1,y1,x2,y2;//起始点与终点坐标
int i;
int mmap[10][10];//定义棋盘
int dir[8][2]={{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}};//定义下一步的八个方向
struct node //结构体,存放当前点的位置坐标,和已经走得的步数
{
int x;
int y;
int steps;
};
node start,finish; //起点和终点
int bfs()
{
memset(mmap,0,sizeof(mmap)); //先将整个棋盘刷成0
node per,cur; //per代表上一个位置。cur代表当前位置
start.steps=0; //起始步数为0
queue<node>q;
q.push(start); //让start先进队
mmap[start.x][start.y]=1; //始点标记为1
while(!q.empty()) //只要队列非空进入循环体
{
per=q.front(); //per是当前的位置
q.pop(); //队首元素出队
if(per.x==finish.x&&per.y==finish.y)//判断是否到达终点
return per.steps;
for(i=0;i<8;i++)
{
cur.x=per.x+dir[i][0];
cur.y=per.y+dir[i][1];
if(cur.x<1||cur.x>8||cur.y<1||cur.y>8)
continue;
mmap[cur.x][cur.y]=1;
cur.steps=per.steps+1;
q.push(cur);
}
}
return -1;
}
接下来是该题目的完整代码
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
int x1,y1,x2,y2;//起始点与终点坐标
int i;
int mmap[10][10];//定义棋盘
int dir[8][2]={{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}};//定义下一步的八个方向
struct node //结构体,存放当前点的位置坐标,和已经走得的步数
{
int x;
int y;
int steps;
};
node start,finish; //起点和终点
int bfs()
{
memset(mmap,0,sizeof(mmap)); //先将整个棋盘刷成0
node per,cur; //per代表上一个位置。cur代表当前位置
start.steps=0; //起始步数为0
queue<node>q;
q.push(start); //让start先进队
mmap[start.x][start.y]=1; //始点标记为1
while(!q.empty()) //只要队列非空进入循环体
{
per=q.front(); //per是当前的位置
q.pop(); //队首元素出队
if(per.x==finish.x&&per.y==finish.y)//判断是否到达终点
return per.steps;
for(i=0;i<8;i++)
{
cur.x=per.x+dir[i][0];
cur.y=per.y+dir[i][1];
if(cur.x<1||cur.x>8||cur.y<1||cur.y>8)
continue;
mmap[cur.x][cur.y]=1;
cur.steps=per.steps+1;
q.push(cur);
}
}
return -1;
}
int main()
{
int mmin,t1,t2;
char s1,s2;
while(scanf("%c%d %c%d",&s1,&t1,&s2,&t2)!=EOF)
{
getchar();
x1=s1-'a'+1;
y1=t1;
x2=s2-'a'+1;
y2=t2;
start.x=x1;
start.y=y1;
finish.x=x2;
finish.y=y2;
if(start.x==finish.x&&start.y==finish.y)
mmin=0;
else
mmin=bfs();
printf("To get from %c%d to %c%d takes %d knight moves.\n",s1,t1,s2,t2,mmin);
}
return 0;
}