Poj-1915 Knight Moves-双向广度优先搜索

问题描述:
Your task is to write a program to calculate the minimum number of moves needed for a knight to reach one point from another, so that you have the chance to be faster than Somurolov.
For people not familiar with chess, the possible knight moves are shown in Figure 1.

问题大意:
骑士遍历问题,给出起始位置和目标位置,问从起始位置到目标位置的最少移动次数
AC代码:

int dirx[8] = {-2,-2,-1,1,2,2,1,-1};
int diry[8] = {-1,1,2,2,1,-1,-2,-2};
struct P//位置
{
    int x;
    int y;
};
P s,e;//起始、目标
int n;
int fstep[310][310],bstep[310][310];//fstep[i][j]为正向搜索到(i,j)的步数,bstep[i][j]为逆向搜索到(i,j)的步数
int bfs_2(P s,P e)
{
    if(s.x == e.x && s.y == e.y)//特判,防止漏解
        return 0;
    queue<P> q1;//正向
    queue<P> q2;//逆向
    memset(fstep,-1,sizeof(fstep));//初始化为-1
    memset(bstep,-1,sizeof(bstep));//初始化为-1
    q1.push(s);//将起始点入队
    q2.push(e);//将目标点入队
    fstep[s.x][s.y] = 0;//更新步数
    bstep[e.x][e.y] = 0;//更新步数
    while(!q1.empty() && !q2.empty())//如果有某一个队列为空,就说明那一个方向的搜索无法进行下去,问题无解
    {
        P p,next_p;//当前点,下一个点
        if(!q1.empty())//判断队列是否为空
        {
            p = q1.front();//取队首
            q1.pop();//出队
            for(int i = 0; i <= 7; ++i)//向8个方向进行扩展
            {
                next_p.x = p.x + dirx[i];
                next_p.y = p.y + diry[i];
                if(next_p.x < 0 || next_p.x > n - 1 || next_p.y < 0 || next_p.y > n - 1)//越界
                    continue;
                if(fstep[next_p.x][next_p.y] == -1)//如果正向没有搜到此点
                {
                    q1.push(next_p);//入队
                    fstep[next_p.x][next_p.y] = fstep[p.x][p.y] + 1;//更新步数
                }
                if(bstep[next_p.x][next_p.y] != -1)//如果逆向已经搜到此点
                    return fstep[next_p.x][next_p.y] + bstep[next_p.x][next_p.y];//搜索成功
            }
        }
        if(!q2.empty())//判断队列是否为空
        {
            p = q2.front();//取队首
            q2.pop();//出队
            for(int i = 0; i <= 7; ++i)//向8个方向进行扩展
            {
                next_p.x = p.x + dirx[i];
                next_p.y = p.y + diry[i];
                if(next_p.x < 0 || next_p.x > n - 1 || next_p.y < 0 || next_p.y > n - 1)//越界
                    continue;
                if(bstep[next_p.x][next_p.y] == -1)//如果逆向没有搜到此点
                {
                    q2.push(next_p);//入队
                    bstep[next_p.x][next_p.y] = bstep[p.x][p.y] + 1;//更新步数
                }
                if(fstep[next_p.x][next_p.y] != -1)//如果正向已经搜到此点
                    return bstep[next_p.x][next_p.y] + fstep[next_p.x][next_p.y];//搜索成功
            }
        }
    }
}
int main()
{
    int _;
    cin >> _;
    while(_--)//多组数据
    {
        cin >> n >> s.x >> s.y >> e.x >> e.y;
        cout << bfs_2(s,e) << endl;
    }
    return 0;
}

解决方法:
双向广度优先搜索:从起始状态和目标状态开始,同时向中间状态扩展,如果生成了同一个状态,则搜索成功

猜你喜欢

转载自blog.csdn.net/suntengnb/article/details/79949712
今日推荐