NPU 17届程序设计 1043 跳马

1043.跳马

时限:1000ms 内存限制:10000K  总时限:3000ms
描述
在国际象棋中,马的走法与中车象棋类似,即俗话说的“马走日”,下图所示即国际象棋中马(K)在一步能到达的格子(其中黑色的格子是能到达的位置)。

现有一200*200大小的国际象棋棋盘,棋盘中仅有一个马,给定马的当前位置(S)和目标位置(T),求出马最少需要多少跳才能从当前位置到达目标位置。
 
输入
本题包含多个测例。输入数据的第一行有一个整数N(1<=N<=1000),表示测例的个数,接下来的每一行有四个以空格分隔的整数,分别表示马当前位置及目标位置的横、纵坐标C(x,y)和G(x,y)。坐标由1开始。
 
输出
对于每个测例,在单独的一行内输出一个整数,即马从当前位置跳到目标位置最少的跳数。
 
输入样例
2
1 1 2 1
1 5 5 1
 
输出样例
3
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();
	}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值