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; }