上次我们说到了深搜
这次我们来讲讲广搜。
广搜原理
广搜,顾名思义,是多管齐下、广撒网的一种搜索方法
如果广搜是一个人,那么她一定很贪心,而且喜新厌旧!她从一点出发去旅游,先把与起点相邻的地方全部游览一遍,然后再把与她刚游览过的景点相邻的景点全都游览一边……一直这样,直至所有的景点都游览一遍。
广搜属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。类似树的按层遍历,其过程为:首先访问初始点Vi,并将其标记为已访问过,接着访问Vi的所有未被访问过可到达的邻接点Vi1、Vi2…Vit,并均标记为已访问过,然后再按照Vi1、Vi2…Vit 的次序,访问每一个顶点的所有未被访问过的邻接点,并均标记为已访问过,依此类推,直到图中所有和初始点Vi有路径相通的顶点都被访问过为止。
我们来举一个栗子: 看洛谷的p1135奇怪的电梯
传送门:https://www.luogu.com.cn/problem/P1135#submit
其间这道题用dfs,bfs(dp),Bellman-Ford,Floyd,spfa,Dijkstra 都可以做
但我们讲的就是广搜嘛
讲解如下:
BFS——广度优先搜索
用一个队列,维护节点和步数。
开始入队(A,0),然后把上、下入队(合法的话),直到第一次出现 B,其实就是不记录 dis 还不排序的 Dijkstra,记得打标记。
正确性:由于边权全部相等(都是 11),不需要用堆来进行排序(Dijkstra),直接用队列即可。
时间复杂度 O(n),代码几乎同 SPFA(仅实现不同),是 Dijkstra 去掉堆优化(log n)的复杂度。
代码如下:
#include<bits/stdc++.h>
int n,a,b,k[201];
bool f,u[201];//u 是标记
int ri(){
int x=0;
char c=getchar(),f=1;
while(c<'0'||c>'9'){
if(c=='-')
f=-f;
c=getchar();
}
while(c<='9'&&c>='0')
x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
struct node{
int x,y;
};
std::queue<node>q;
int bfs(){
q.push(node{a,0});//入队
u[a]=1;
while(!q.empty()){
int x=q.front().x,y=q.front().y;
q.pop();
if(x==b)
return y;//到了 B
int xn=x+k[x],yn=y+1;
if(xn<=n&&xn>0&&!u[xn])//上
q.push(node{xn,yn}),u[xn]=1;
xn-=2*k[x];
if(xn<=n&&xn>0&&!u[xn])//下
q.push(node{xn,yn}),u[xn]=1;
}
return-1;
}
int main(){
n=ri(),a=ri(),b=ri();
for(int i=1;i<=n;i++)
k[i]=ri();
printf("%d",bfs());
return 0;
}