Knight Moves

元气小坏坏 提交于 2019-12-02 23:18:35

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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!