广度优先搜索的优化与技巧

例题:P1397 八数码难题

双向BFS

普通BFS

双向BFS

所谓双向广度优先搜索指的是搜索沿两个方向同时进行

正向搜索:从初始点向目标点搜索;

逆向搜索:从目标点向初始点搜索;

从正反两个方向搜索,理论上可以节省二分之一的搜索量,从而提高搜索速度,节约内存空间。

从初始状态和目标状态向两个方向同时进行扩展,如果两颗解答树在某个节点发生一次重合,即可终止此搜索过程,则该节点所连接的两条路径所拼成的路径就是最优解

●双向广度优先搜索通常有两种搜索方法:

①、两个方向交替扩展;

②、选择结点个数较少的那个方向先扩展;

●实现方法:

建立两个队列分别拓展两个方向出发的状态。

每次while循环时只扩展正反两个方向中节点数目较少的一个,可以使两边的发展速度保持一定的平衡,从而减少总扩展节点的个数,加快搜索速度。

例题代码

#include<iostream>
#include<map>
#include<queue>
#include<cstring>
using namespace std;
map<string, int> ma,mb;
struct nod
{
    string a;
    int x, y;
};
queue<nod> qa,qb;
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};

int main()
{
    string aim = "123804765",a;
    cin >> a;
    if(a==aim)
    {
        cout << "0";
        return 0;
    }
    for (int i = 0; i < 9;i++)
    {
        if(a[i]=='0')
            qa.push({a, i / 3, i % 3});
    }
    qb.push({aim, 1, 1});
    ma[a] = mb[aim] = 0;
    while(!qa.empty()||!qb.empty())
    {
        if(qa.size()<qb.size())
        {
            string temp = qa.front().a;
            int x1 = qa.front().x;
            int y1 = qa.front().y;
            qa.pop();
            for (int i = 0; i < 4;i++)
            {
                if(x1+dx[i]<0||x1+dx[i]>2||y1+dy[i]<0||y1+dy[i]>2)
                    continue;
                string b = temp;
                swap(b[x1 * 3 + y1], b[(x1 + dx[i]) * 3 + y1+dy[i]]);
                if(ma[b]!=0)
                    continue;
                if(mb[b]!=0)
                {
                    cout << ma[temp] + mb[b] + 1;
                    return 0;
                }
                ma[b] = ma[temp] + 1;
                qa.push({b, x1 + dx[i], y1 + dy[i]});
            }
        }
        else
        {
            string temp = qb.front().a;
            int x1 = qb.front().x;
            int y1 = qb.front().y;
            qb.pop();
            for (int i = 0; i < 4;i++)
            {
                if(x1+dx[i]<0||x1+dx[i]>2||y1+dy[i]<0||y1+dy[i]>2)
                    continue;
                string b = temp;
                swap(b[x1 * 3 + y1], b[(x1 + dx[i]) * 3 + y1+dy[i]]);
                if(mb[b]!=0)
                    continue;
                if(ma[b]!=0)
                {
                    cout << ma[b] + mb[temp] + 1;
                    return 0;
                }
                mb[b] = mb[temp] + 1;
                qb.push({b, x1 + dx[i], y1 + dy[i]});
            }
        }
    }
    return 0;
}

双端队列BFS

P4667 [BalticOI 2011 Day1]Switch the Lamp On

类似优先队列优化的d j最短路,每次用未被标记最小的值去更新其他点。

边权只有0、1,可用双端队列代替优先队列

边权为0,插到队头;边权为1,插入队尾,这样就省去了排序操作,保证队首最小

例题代码

#include<deque>
#include<cstring>
#include<iostream>
using namespace std;
struct nod
{
    int x, y;
};
char sq[505][505];
deque<nod> q;
int dx[4] = {1, 1, -1, -1};
int dy[4] = {1, -1, 1, -1};
int rx[4] = {0, 0, -1, -1};
int ry[4] = {0, -1, 0, -1};
char ch[5] = "\\//\\";
bool vis[505][505];
int dist[505][505];
int n, m;

void bfs()
{        
    memset(vis, 0, sizeof(vis));
    memset(dist, 0x3f, sizeof(dist));
    q.push_front({0, 0});
    dist[0][0] = 0;
    while(!q.empty())
    {
        int x1 = q.front().x;
        int y1 = q.front().y;
        q.pop_front();
        if(vis[x1][y1])
            continue;
        vis[x1][y1] = 1;
        for (int i = 0; i < 4;i++)
        {
            int x2 = x1 + dx[i];
            int y2 = y1 + dy[i];
            if(x2<0||x2>n||y2<0||y2>m)
                continue;
            int xs = x1 + rx[i];
            int ys = y1 + ry[i];
            int d = dist[x1][y1];
            if(sq[xs][ys]!=ch[i])
                d++;
            if(d<dist[x2][y2])
            {
                dist[x2][y2] = d;
                if(sq[xs][ys]!=ch[i])
                    q.push_back({x2, y2});
                else
                    q.push_front({x2, y2});
            }
        }
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 0; i < n;i++)
    {
        for (int j = 0; j < m;j++)
            cin >> sq[i][j];       
    }  
    bfs();
    if(dist[n][m]==0x3f3f3f3f)
        cout << "NO SOLUTION"<<endl;
    else
        cout << dist[n][m]<<endl;
    return 0;
}
posted @ 2020-08-08 20:02  DSHUAIB  阅读(396)  评论(0)    收藏  举报