Knight Moves
https://loj.ac/problem/10028
题目描述
在一个\(L×L\)的棋盘中,给出马的初始位置和终止位置,求最少跳多少步从初始到终止。
思路
\(bfs\)的模板题,不过为了提高速度我们可以采用双向宽度搜索,分别从起始位置和终止位置进行\(bfs\),在判断何时两个\(bfs\)在同一地点相遇即可。为了避免效率过低,我们可以每次选择队列中节点少的进行拓展。
代码
#include <bits/stdc++.h>
using namespace std;
struct aa
{
int x,y;
}st,ed;
int dx[10]={1,1,-1,-1,2,2,-2,-2};
int dy[10]={2,-2,2,-2,1,-1,1,-1};
int dis[3][330][330],l,ans;
queue<aa>q[3];
bool vis[3][330][330];
bool expand(int k)
{
aa now=q[k].front();q[k].pop();
int d=dis[k][now.x][now.y];
for(int i=0;i<8;i++)
{
aa nex;
nex.x=now.x+dx[i];nex.y=now.y+dy[i];
if(nex.x<=0||nex.x>l||nex.y<=0||nex.y>l||vis[k][nex.x][nex.y])
continue ;
vis[k][nex.x][nex.y]=1;
dis[k][nex.x][nex.y]=d+1;
q[k].push(nex);
if(vis[1-k][nex.x][nex.y])
{
ans=dis[k][nex.x][nex.y]+dis[1-k][nex.x][nex.y];
return 1;
}
}
return 0;
}
void bfs()
{
if(st.x==ed.x&&st.y==ed.y)
{ans=0;return ;}
vis[0][st.x][st.y]=1;q[0].push(st);
vis[1][ed.x][ed.y]=1;q[1].push(ed);
while(!q[0].empty()&&!q[1].empty())
{
if(q[0].size()<q[1].size())
{
if(expand(0))return ;
}
if(q[1].size()<=q[0].size())
{
if(expand(1))return ;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
while(!q[0].empty())q[0].pop();
while(!q[1].empty())q[1].pop();
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
scanf("%d",&l);
scanf("%d%d%d%d",&st.x,&st.y,&ed.x,&ed.y);
bfs();
printf("%d\n",ans);
}
return 0;
}