广搜与队列浅谈

一、引入

广搜,即广度优先搜索算法,是搜索的一种。它和深搜的主要区别体现在访问次序上。我们先介绍一种数据结构,在简介一下广搜模板,最后讲解几道例题。

二、队列

队列(queue)是一种常见的数据结构。我们能从队尾插入元素,从对头取出元素。这恰恰和日常生活中的排队一样,只能从最后面开始排,排到最前面才轮到你。我们发现,如果开始结束队列都为空的话,最先放入的元素总是第一个被取出,第二个被放入的元素第二个被取出……最后一个被放入的元素最后一个被取出。因此,队列也有“先进先出表”之称。我们用两个变量分别记录对头和队尾的位置,类似于栈,我们就可以用数组实现队列了。
我们发现,实现队列的数组中每个位置最多只能用一次,因此会造成空间浪费。我们可以采用循环队列的方式,即当对列满了的时候,就可以把元素插入数组前端从而节省空间。我们也可以采用STL里的queque。

三、广度优先搜索算法

我们先把起点加入队列,每一步我们取队头。每一个决策点都可以引出若干个子决策点。不同于深搜,在枚举子决策点时我们不立即处理子决策点,而是把它加入队尾,等排在它前面的决策点都处理完后,也就是说当到它到达队头时再处理。从这里可以看出,广搜与队列有着很大的联系
如果定义一个决策点的深度为其祖先决策点的个数。不难发现广搜是先把深度相同的决策点处理完的,这与深搜优先处理更深的决策点的思想不同,可以想象它处理决策点的次序是“横向”的,因此称之为广度优先搜索。
下面展示一段伪代码:

queue<node>q;
void bfs(){
   
	node u,v;
	q.push(起点); vi[起点]=1;
	while(q.size()){
   
		u=q.front();
		for(v为u的子决策点){
   
			更新v;
			if(!vi[v]){
   
				vi[v]=1;
				q.push(v);
			}
		}
	}
	return;
}

四、经典例题

1.滑动窗口

有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。

这是一道单调队列的模板题。以求最大值为例,我们弄一个队列存当前枚举到的元素及其前(k-1)个元素。每当枚举到后一个元素时,我们只需要把队头出队,再将这个元素入队就好了。但这种O(nk)的算法无法通过本题,我们便需要加以优化。如果对于i<j有a[i]<a[j],便会有i不比j更优。因为当i在队列时,j一定也在队列,最大值取不到a[i];当j在队列时,i不一定也在队列里。也就是说,j比i生存能力更强。因此我们在加入一个元素前,先把队尾比它小的元素剔除掉。这样,维护出来的是一个单调递减的队列,队头便是最大值。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int n,k,a[1000001];
deque<int>q; 
/*这里用的是双端队列,队列的一种简单变形,
即能从两端同时加入、弹出或访问*/
int main(){
   
	scanf("%d%d",&n,&k
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值