POJ1915 双向广度优先搜索

双向广度优先搜索算法:初始状态(正向搜索)和目标状态(逆向搜索)同时向中间搜,当两个方向的搜索生成同一子状态时,搜索结束;一般用来解决最小等最优问题;

如何判断是否生成了同一子状态:(1)用标记数组,若某一状态未被遍历到,则为0,正向遍历到为1,逆向遍历到为2,当遍历到某一状态时,判断一下其对应标记数组的值;(2)本题(poj1915)代码;

#include
#include
#include;
using namespace std;
#define Maxn 309
struct node
{
    int x,y;
};//坐标节点
int n;//图的大小
int fstep[Maxn][Maxn],bstep[Maxn][Maxn];//记录正向搜索和逆向搜索步数
int dir[8][2] = {-1,-2,-2,-1,-2,1,-1,2,1,2,2,1,2,-1,1,-2};
bool isok(node a)
{
    if (a.x < 0 || a.x >= n || a.y < 0 || a.y >= n)
        return false;
    return true;
}
int BBFS(node a,node b)
{
    if (a.x == b.x && a.y == b.y)
    {
        return 0;
    }//如果起点和终点一样,则返回0
    int i,j;
    queueq1,q2;
    for (i = 0; i < n; ++i)
    {
        for (j = 0; j < n; ++j)
            fstep[i][j] = bstep[i][j] = -1;
    }//步数初始化
    fstep[a.x][a.y] = 0;//起点步数=0
    bstep[b.x][b.y] = 0;//终点步数=0
    q1.push(a);
    q2.push(b);
    while (!q1.empty() && !q2.empty())
    {
        /*如果起点能够到达终点的话,那么两个队列是不可能为空的,如果有一个队列为空
        表明某一方向的搜索已经无法再继续下去,无路可走了,换言之,也没有路可以走
        到这里,说明起点与终点是不可达的,就可以结束搜索了*/
        node tt,t1,t2;
        if (!q1.empty())
        {
            t1 = q1.front();
            q1.pop();
            for (i = 0; i < 8; ++i)
            {
                tt.x = t1.x + dir[i][0];
                tt.y = t1.y + dir[i][1];
                if (isok(tt))
                {
                    if (fstep[tt.x][tt.y] == -1)
                    {
                        fstep[tt.x][tt.y] = fstep[t1.x][t1.y] + 1;
                        q1.push(tt);
                    }
                    if (bstep[tt.x][tt.y] != -1)//判断是否生成了同一子状态
                        return fstep[tt.x][tt.y] + bstep[tt.x][tt.y];
                    //达到子状态的那一步上面已经走了,故返回值不需要再加一
                }
            }
        }
        if (!q2.empty())
        {
            t2 = q2.front();
            q2.pop();
            for (i = 0; i < 8; ++i)
            {
                tt.x = t2.x + dir[i][0];
                tt.y = t2.y + dir[i][1];
                if (isok(tt))
                {
                    if (bstep[tt.x][tt.y] == -1)
                    {
                        bstep[tt.x][tt.y] = bstep[t2.x][t2.y] + 1;
                        q2.push(tt);
                    }
                    if (fstep[tt.x][tt.y] != -1)//判断是否生成了同一子状态
                        return bstep[tt.x][tt.y] + fstep[tt.x][tt.y];
                    //达到子状态的那一步上面已经走了,故返回值不需要再加一
                }
            }
        }
    }
}
int main()
{
    int t,ans;
    struct node a,b;
    while (~scanf("%d",&t))
    {
        while (t--)
        {
            scanf("%d",&n);
            scanf("%d%d%d%d",&a.x,&a.y,&b.x,&b.y);
            ans = BBFS(a,b);
            printf("%d\n",ans);
        }
    }
    return 0;
}
/*
这题其实还可以再优化一下,就是入队列时,可以用一个标记数组判断一下该状态是否已经在队列里了
只不过要用到两个标记数组分别判断,这样写的话,代码感觉有点乱,反正能过,就算了,知道就行
*/

你可能感兴趣的:(搜索,双向广搜)