1043.跳马
时限:1000ms 内存限制:10000K 总时限:3000ms
描述
在国际象棋中,马的走法与中车象棋类似,即俗话说的“马走日”,下图所示即国际象棋中马(K)在一步能到达的格子(其中黑色的格子是能到达的位置)。
现有一200*200大小的国际象棋棋盘,棋盘中仅有一个马,给定马的当前位置(S)和目标位置(T),求出马最少需要多少跳才能从当前位置到达目标位置。
![](http://noj.cn/images/problemimages/knightmove.bmp)
现有一200*200大小的国际象棋棋盘,棋盘中仅有一个马,给定马的当前位置(S)和目标位置(T),求出马最少需要多少跳才能从当前位置到达目标位置。
输入
本题包含多个测例。输入数据的第一行有一个整数N(1<=N<=1000),表示测例的个数,接下来的每一行有四个以空格分隔的整数,分别表示马当前位置及目标位置的横、纵坐标C(x,y)和G(x,y)。坐标由1开始。
输出
对于每个测例,在单独的一行内输出一个整数,即马从当前位置跳到目标位置最少的跳数。
输入样例
2
1 1 2 1
1 5 5 1
1 1 2 1
1 5 5 1
输出样例
3
4
4
本题原理上与电子老鼠问题类似,均为求最小步数,因此使用广搜法,用队列储存数据。
不同的是这一次有8个方向,而且地图上没有障碍物,因只需要判断是否出界即可。其次,最快的路线不存在重复到达同一个点的情况,因此使用二维数组将到达过的点标记。为满足的题目是输入要求,需要创建数组储存数据,先将第一组数据输入处理,再将标记地图与队列初始化重复使用。
本题的算法可以作为象棋的电脑程序的一部分,用以判断马将军或者吃掉对方重要棋子所需最小步数,并配合极大极小算法判断。
#include<iostream>
#include<queue>//本题使用广搜,需要队列头文件
using namespace std;
struct coor
{//建立坐标的结构体
queue<int> y;
queue<int> x;
}coor;
char used[200][200];//标记该位置已经被走过
char step[200][200];//记录到达该位置所需步数
int sy,sx;
int ty,tx;
//起点和终点使用全局变量
void stepcount(int isy,int isx,int ity,int itx);
void init();
int bfs();
int ymove(int y,int i);
int xmove(int x,int i);
void allinit();
int main()
{
int n,i;
int isy[20],isx[20],ity[20],itx[20];//创建一系列数组储存输入的数据
cin>>n;
for (i = 0;i < n;i++)
{
cin>>isy[i]>>isx[i]>>ity[i]>>itx[i];
}
for (i = 0;i < n;i++)
{
stepcount(isy[i],isx[i],ity[i],itx[i]);
}
}
void stepcount(int isy,int isx,int ity,int itx)
{
int num;
sy = isy - 1;
sx = isx - 1;
ty = ity - 1;
tx = itx - 1;
init();
num = bfs();
cout<<num<<endl;
allinit();
}
void init()
{//初始化,将起点加入队列并标记
coor.y.push(sy);
coor.x.push(sx);
used[sy][sx] = 1;
step[sy][sx] = 0;
}
int bfs()
{
int uy,ux,vy,vx,i;
while (!coor.y.empty() && !coor.x.empty())
{//当队列不为空时将队首元素取出
uy = coor.y.front();
ux = coor.x.front();
coor.y.pop();
coor.x.pop();
for (i = 1;i < 9;i++)
{//一共有8种方向可以移动,用函数来计算移动后的位置
vy = ymove(uy,i);
vx = xmove(ux,i);
if (vy == ty && vx == tx)
{//如果已经到达终点,则返回所需步数
step[ty][tx] = step[uy][ux] + 1;
return (step[ty][tx]);
}
if (vy>=0 && vy<200 && vx>=0 && vx<200 && used[vy][vx]==0)
{//如果没到达重点且该点未出界、未被使用则加入队列等待下一次调用
coor.y.push(vy);
coor.x.push(vx);
used[vy][vx] = 1;//标记原来的起点
step[vy][vx] = step[uy][ux] + 1;
}
}
}
}
int ymove(int y,int i)
{//8个方向Y轴坐标的处理
if (i==1 || i==8)
{
y = y - 2;
return (y);
}
if (i==2 || i==7)
{
y = y - 1;
return (y);
}
if (i==3 || i==6)
{
y = y + 1;
return (y);
}
if (i==4 || i==5)
{
y = y + 2;
return (y);
}
}
int xmove(int x,int i)
{//8个方向的X轴坐标的处理
if (i==1 || i==4)
{
x = x + 1;
return (x);
}
if (i==2 || i==3)
{
x = x + 2;
return (x);
}
if (i==5 || i==8)
{
x = x - 1;
return (x);
}
if (i==6 || i==7)
{
x = x - 2;
return (x);
}
}
void allinit()
{
int i,j;
for (i = 0;i < 200;i++)
{//将标记数组还原为全0状态,防止下一次运行程序时出错
for (j = 0;j < 200;j++)
{
used[i][j] = 0;
}
}
while (!coor.y.empty() && !coor.x.empty())
{//清除队列中的剩余元素
coor.y.pop();
coor.x.pop();
}
}