BFS 广度优先搜索(队列)
目录
一. 基本实现
a .首先选择一个顶点作为起始结点,并将其染成灰色,其余结点为白色。
b. 将起始结点放入队列中。 并找出所有与之邻接的结点。
c. 从队列首部选出一个顶点,将找到的邻接结点放入队列尾部,
将已访问过结点涂成黑色。如果顶点的颜色是灰色,表示已经放入了队列,
如果顶点的颜色是白色,表示还没有发现 d. 按照同样的方法处理队列中的下一个结点。
基本就是出队的顶点变成黑色,在队列里的是灰色,还没入队的是白色。
例如,从顶点1开始进行广度优先搜索:
- 初始状态,从顶点1开始,队列={1}
- 访问1的邻接顶点,1出队变黑,2,3入队,队列={2,3,}
- 访问2的邻接结点,2出队,4入队,队列={3,4}
- 访问3的邻接结点,3出队,队列={4}
- 访问4的邻接结点,4出队,队列={ 空} 结点5对于1来说不可达。
二. 双端队列
普通队列用于边权为定值的最短路搜索。
且每次到达都是最优的决策(不用取min)。
因为所有状态按照 入队的先后顺序 具有 层次单调性,每次扩展,都往外走一步,
满足从起始到该状态的最优性(不用取min/也不用比大小,如果如此失去了意义)。
双端队列可以进行边权为1/0的最短路搜索。
对于一条边 u 到 v ,如果此边权值为0,我们将它 push_front(v) ,否则 push_back(k),
每次取队首,这样我们保证了单调性(即每次优先选择最优的)。
注意细节:把某一方格对角两点的连线看成边,若和原状态匹配边权为0,否则为1。
我们放入队列里的还有u,这样才能做到将每次取出的时候更新,
也就是说在队列中放入二元组(u,v)。复杂度:O(r*c)。
【例题】洛谷 p2243 电路维修
有一天 Mark 和James 的飞行车没有办法启动了,经过检查发现原来是电路板的故障。
飞行车的电路板设计很奇葩,如下图所示:
对于每组测试数据,在单独的一行输出一个正整数,表示所需的缩小旋转次数。
如果无论怎样都不能使得电源和发动机之间连通,输出 NO SOLUTION。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<deque> //双端队列
using namespace std;
const int MAXX=550;
int dis[MAXX][MAXX];
bool vis[MAXX][MAXX],Map[MAXX][MAXX];
int dx[4]={1,-1,1,-1};
int dy[4]={1,-1,-1,1}; //矩形中的边的扩展方向
char ss[MAXX];
int t,r,c;
inline bool checks(int x,int y){ //检查是否到边界
if(x>=1&&y>=1&&x<=r+1&&y<=c+1)
return true;
return false;
}
inline int edges(int x,int xx,int y,int yy){
if((xx<x&&yy<y)||(xx>x&&yy>y))
return !Map[min(x,xx)][min(y,yy)];
else return Map[min(x,xx)][min(y,yy)];
}
inline void bfs(){
Map[0][0]=1; //广搜起点
deque< pair < pair<int ,int> ,p