题目链接:http://acm.ocrosoft.com/problem.php?cid=1694&pid=2
题目描述
佳佳是一名出色的棋手,声称任何人他都可以从一个位置到另一个骑士这么快。你能打败他吗?
问题
你的任务是写一个程序来计算一个骑士达到从另一点所需要的最少步数。
对于不熟悉象棋的人,可能的骑士动作如图所示。
输入
输入开始与一个单一的行本身的情况下。
下一步跟踪N个场景。每个场景由三行包含整数。第一行指定棋盘边的长度L(4 < L = < 300)。整个板尺寸L×L的第二和第三行包含整数对{ 0,…,L-1 } * { 0,…,L-1 }指定开始和结束位置的骑士。整数由一个空格隔开。您可以假定这些位置是该方案的棋盘上的有效位置.。
输出
对于输入的每一个场景,你必须计算从起点到终点的最小的骑士移动量.。如果起点和终点相等,距离为零。距离必须写在一行。
样例输入
3
8
0 0
7 0
100
0 0
30 50
10
1 1
1 1
样例输出
5
28
0
思路
这道题是一道广搜剪枝题(虽然好像不剪枝也能过),这道题的剪枝方法主要是起点和终点双边扩展,也就是我们分别从起点和终点bfs当他们遍历到同一个点时停下,即可得到答案
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int sx,sy,dx,dy;//分别代表起点坐标和终点坐标
int dist[303][303][2];//第三维0代表起点到该点距离,1代表终点到该点的距离
int d[8][2]={
{2,1},{2,-1},{-2,-1},{-2,1},{1,2},{1,-2},{-1,2},{-1,-2}};//方向变量
queue<int>px,py,qx,qy;//建立终点和起点坐标的队列
int bfs()
{
if(sx==dx&&sy==dy)
return 0;
while(!px.empty())//清空队列
px.pop(),py.pop();
while(!qx.empty())
qx.pop(),qy.pop();
px.push(sx);//终点起点入队
py.push(sy);
qx.push(dx);
qy.push(dy);
memset(dist,-1,sizeof(dist));//距离初始化为-1
dist[sx][sy][0]=dist[dx][dy][1]=0;//终点和起点距离初始化为0
while((!px.empty())||(!qx.empty()))//队列非空
{
if(px.size()<qx.size())//选择数量少的队列
{
int x=px.front();
int y=py.front();
px.pop();//队首出队
py.pop();
for(int i=0;i<8;i++)
{
int xx=x+d[i][0],yy=y+d[i][1];//向不同方向
if(xx>=0&&yy>=0&&xx<n&&yy<n&&dist[xx][yy][0]==-1)//该点有效且未遍历
{
dist[xx][yy][0]=dist[x][y][0]+1;//距离更新
if(dist[xx][yy][1]!=-1)//当该点终点和起点都遍历到,即重合,距离相加
{
return dist[xx][yy][0]+dist[xx][yy][1];
}
px.push(xx);//新点入队
py.push(yy);
}
}
}
else
{
int x=qx.front();
int y=qy.front();
qx.pop();
qy.pop();
for(int i=0;i<8;i++)
{
int xx=x+d[i][0],yy=y+d[i][1];
if(xx>=0&&yy>=0&&xx<n&&yy<n&&dist[xx][yy][1]==-1)
{
dist[xx][yy][1]=dist[x][y][1]+1;
if(dist[xx][yy][0]!=-1)
{
return dist[xx][yy][0]+dist[xx][yy][1];
}
qx.push(xx);
qy.push(yy);
}
}
}
}
return 0;
}
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%d%d%d%d%d",&n,&sx,&sy,&dx,&dy);
printf("%d\n",bfs());
}
return 0;
}