BFS

BFS

广搜及优化技巧

一、基本算法
     如果我们把问题状态空间类比成一个图,那么广度优先搜索就相当于对这个图的广度优先遍
历。类似地,我们依然借助一个队列来实现广度优先搜索,起初队列中仅包含起始状态,在广度
先搜索的过程中,我们不断地从队头取出状态,对于该状态面临的所有分支,把沿着每一条分支到
达的下一个状态(如果尚末访问过或者能够被更新成更优的解)插入队尾。重复执行上述过程直
到队列为空

 

 

二、模板

struct node{
    // 你要表示的状态,例如:坐标
}
node _node(/*参数*/){
    node r;
    //初始化
    return r;
}
/*
例如:
struct node{
    int x,y;
}
node _node(int x,int y){
    node r;
    r.x=x;
    r.y=y;
    return r;
}
*/
queue<node>q;
bool vis[...]...[...];//判重数组,保证每个状态只访问一次。
void bfs(node s/*起始元素*/){
    q.push(s);
    vis[...]...[...]=1;//初始状态纪录
    while(!q.empty()){
        node head=q.front();
        q.pop();
        for(...){//遍历所有能到达的状态
            node now=_node(head...)//新状态
            if(...now...&&!vis[...]...[...]){//新状态合法且没被访问过
                q.push(now);
                vis[...]...[...]=1;//新状态纪录。
            }
        }
    }
}

 

【参考例题】

1.  U68364 _GC滑迷宫

2.  P1605 迷宫

 

 

三、优化   

1.双端队列BFS

    原来我们的BFS是只从队首入队,现在我们也可以从队尾入队

    举个栗子:

         我们之前已经把问题转化成一个无向图了,假设它的边权只有1和0,那么入队的时候,1从队首入队,0从队尾入队,保证队列的两段性和单调性

 

【例题】   1448:【例题1】电路维修

 

 

 

2.Hash判重

        深度优先搜索的另外一类应用—给出起始和目标状态,以及状态转移的规则,要求找到一条到达目标状态的路径或者方法,这类问题我们称它为路径寻找问题(例如,走迷宫问题).
        解决这类问题最有效的算法是选取合适的方法构造Hash表
        在路径寻找问题中,经常会遇到走回头路的问题,所以在搜索的过程中都必须做一件事,就是判重
        一个好的Hash 函数可以在很大程度上提高程序的整体时间效率和空间效率


Hash表的构造方法一般有:
①状态压缩---运用2进制数来记录状态
②直接取余法---选取一个质数M作为除数
③平方取中法---计算关键值平方,再取中间r位形成一个大小为2^t的表
④折叠法---把所有字符的ASCII码加起来。

 

【例题】 1449:【例题2】魔板

 

 

 

3.双向宽度搜索
        从正反两个方向进行宽度优先搜索,可以大大减少搜索量,提高搜索速度
       从初始状态和目标状态两个方向同时进行扩展,如果两棵解答树在某个结点第一次发生重合,即可终止此搜索过程,则该结点所连接的两条路径所拼成的路径就是最优解

(1)双向宽度优先搜索通常有两种搜索方法
①两个方向交替扩展
②选择结点个数较少的那个方向先扩展

      方法②只需要略加修改控制结构,每次 while循环时只扩展正反两个方向中结点数目较少的那一个,可以使两边的发展速度保持一定的平衡,从而减少总扩展结点的个数,加快搜索速度
      很明显,方法②优于方法①
(2)算法说明
      设置两个队列q[2][maxn],分别表示正向和逆向的扩展队列
      设置两个头指针l[2]分别表示正向和逆向将扩展结点的头指针
      设置两个尾指针r[2]分别表示正向和逆向的尾指针

 

【例题】  1450:【例 3】Knight Moves

 

posted @ 2019-06-11 09:30  晔子  阅读(482)  评论(0编辑  收藏  举报