本题链接:点击打开链接
Knight Moves
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11362 Accepted Submission(s): 6678
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.
e2 e4 a1 b2 b2 c3 a1 h8 a1 h7 h8 a1 b1 c3 f6 f6
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.
PS:本人写的第一个广搜题目,看了很多有关广搜的知识,本题就是用队列知识做的,查阅了许多资料,也看了书,现在对队列知识做下笔记,和大家分享下,也方便自己回顾。
首先我们应该都知道C++队列是一种容器适配器,它符合“先进先出“(First In First Out,FIFO)的数据结构,是一种“公平队列”。
涉及到的头文件: #include <queue> #include <functional>.
队列的建立: queue<int>+队列名
常用操作:
1.队列名.back() 返回一个引用,指向最后一个元素(即为取队尾元素)
2.队列名.empty() 如果队列空则返回为true,否则为false
3.队列名.front() 返回第一个元素 (即为取对头元素)
4.队列名.pop() 删除第一个元素 (即为元素出队操作)
5.队列名.push() 在末尾加入一个元素(即为元素入队操作)
6.队列名.size() 返回队列中元素的个数
7.队列名.top() 返回优先队列中有最高优先级的元素(优先队列中需要用到的)
题意:给出骑士的初始位置和目标位置,计算要移动多少步到达目标位置。按照格式输出即可。
分析:只要我们知道国际象棋中的骑士和中国的象棋中的“马”差不多一样就行,它每次的移动方式也是“日”,唯一一点不同就是没有拌马脚。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
char a[5],b[5];
int vis[10][10]; //标记数组,记录已经走过的位置(用bool型也可)
int dir[8][2]= {{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};//骑士每次可以移动的八个方向
int sx,sy,ex,ey,t; //sx,sy,es,ey分别代表骑士初始位置和目标位置,t记录走的步数
struct node
{
int x,y,temp;
} s,ns;
void bfs(int x,int y)
{
int i,nx,ny;
queue<node>q; //将队列名设为q;
s.x=x;
s.y=y;
s.temp=0;
vis[x][y]=0;
q.push(s); //将第一个元素加入队列中
while(!q.empty())
{
s=q.front(); //再取出队列中的第一个元素赋值给结构体变量s
q.pop(); //删除第一个元素
if(s.x==ex&&s.y==ey) //判断是否已到达目标位置
{
t=s.temp;
return;
}
for(i=0; i<8; i++) //开始游历查找目标位置
{
nx=s.x+dir[i][0];
ny=s.y+dir[i][1];
if(vis[nx][ny]&&nx>0&&nx<9&&ny>0&&ny<9) //注意是否越界和已游历
{
ns.x=nx;
ns.y=ny;
ns.temp=s.temp+1;
vis[nx][ny]=0; //已经游历就标记为0
q.push(ns); //将下一位置元素压入队列中进行判断
}
}
}
}
int main()
{
while(~scanf("%s%s",a,b))
{
memset(vis,1,sizeof(vis)); //记得每次初始化标记数组
sx=a[0]-'a'+1; //因为输入的是字符,所以需要处理一下。
sy=a[1]-'0';
ex=b[0]-'a'+1;
ey=b[1]-'0';
bfs(sx,sy);
printf("To get from %s to %s takes %d knight moves.\n",a,b,t);
}
return 0;
}