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;//新状态纪录。 } } } }
【参考例题】
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]分别表示正向和逆向的尾指针