广搜(bfs)

定义

广度优先算法,简称BFS.是一种图形搜索演算法,简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点,如果发现目标,终止.

与dfs的相似之处与不同

结合深搜理解

相同点:都是将所有的情况遍历

不同之处:dfs是一条路走到死,但是bfs则是放眼所有能到达的地方

bfs的特点也决定了bfs的使用范围

往往bfs比dfs更加高效

比如

0 0 0
0 0 0
0 0 0

我们从左上角遍历到右上角,最少需要多少步(上下左右)?

比较dfs bfs

dfs:所有的路径都要尝试一遍,效率极其低

bfs:我们将所有能到达的地方都存入队列,发现只要4就可以找出答案,相对于dfs效率大大提升

所以

如果将路径列为树的话,那么答案相对深度较小,就适合使用bfs

例题

电路维修

思路:

最短路

明显的最短路

很显然,对于

/

我们从左上到右下耗费的代价是1

否则为0

\

我们从右上到左下耗费的代价是1

否则为0

我们是一定不会利用一个导线1次以上的

那么我们只要建,左上到右下,右上到左下的边,利用最短路就行了

bfs

bfs也差不多

我们以代价为树的深度

我们将对应的代价能到达的区域存入队列,当然,如果之前走过就没有必要再走一遍了

如果搜到了终点就是最优解

#include<bits/stdc++.h>
using namespace std;
struct Jack{
int next,last,ans,x,y,c;
}f[5000000];
bool vis[5000000];
int n,m,tot=0,ed;
inline void put(int x,int y,int c){
f[++tot].x=x;
f[tot].y=y;
f[tot].c=c;
f[tot].next=f[x].last;
f[x].last=tot;
}
inline void search( ){
int i,j,x,y,c;
for(i=1;i<=ed;i++)f[i].ans=0xffffff;
deque<int>q;
q.push_front(1);
vis[1]=0;
f[1].ans=0;
while(!q.empty( )){
x=q.front( );q.pop_front( );
for(i=f[x].last;i>=1;i=f[i].next){
y=f[i].y;c=f[i].c;
if(f[x].ans+c<f[y].ans){
f[y].ans=f[x].ans+c;
if(!vis[y]){
vis[y]=1;
if(c==1)q.push_back(y);
else q.push_front(y);
}
}
}
vis[x]=0;
}
}
int main( ){
std::ios::sync_with_stdio(false);
cin>>n>>m;
char s[510];
int i,j,x1,x2,x3,x4;
ed=(n+1)*(m+1);
for(i=1;i<=n;i++){
cin>>s+1;
for(j=1;j<=m;j++){
x1=(m+1)*(i-1)+j;x2=(m+1)*i+j+1;x3=x1+1;x4=x2-1;
if(s[j]=='\\'){
put(x1,x2,0);
put(x2,x1,0);
put(x3,x4,1);
put(x4,x3,1);
}else{
put(x1,x2,1);
put(x2,x1,1);
put(x3,x4,0);
put(x4,x3,0);
}
}
}
search( );
if(f[ed].ans==0xffffff)cout<<"NO SOLUTION"<<endl;
else cout<<f[ed].ans<<endl;
}

魔板

思路:

我们以次数为树的深度,建立一颗树,进行bfs遍历即可

#include<bits/stdc++.h>
using namespace std;
string want;
map<string,string>m;
queue<string>q;
inline void A(string a){
string s=a;
int i;
for(i=0;i<4;i++)swap(s[i],s[7-i]);
if(!m.count(s)){
m[s]=m[a]+'A';
q.push(s);
}
}
inline void B(string a){
string s=a;
s[0]=a[3],s[1]=a[0],s[2]=a[1],s[3]=a[2],s[4]=a[5],s[5]=a[6],s[6]=a[7],s[7]=a[4];
if(!m.count(s)){
m[s]=m[a]+'B';
q.push(s);
}
}
inline void C(string a){
string s=a;
s[1]=a[6];s[2]=a[1];s[5]=a[2];s[6]=a[5];
if(!m.count(s)){
m[s]=m[a]+'C';
q.push(s);
}
}
inline void bfs(){
q.push("12345678");
m["12345678"]="";
while(!q.empty( )){
A(q.front( ));
B(q.front( ));
C(q.front( ));
if(m.count(want)!=0){
cout<<m[want].size( )<<endl<<m[want];
return;
}
q.pop( );
}
}
int main( ){
char a1;
for(int i=0;i<8;i++)cin>>a1,want+=a1,getchar();
bfs( );
}

走马

思路:

和平时的走马差不多

但是数据庞大,怎么办呢?

这时就引入双端队列,从终点和起点同时进行bfs遍历,如果重复到达一个点,就返回值

#include <bits/stdc++.h>
using namespace std;
struct node{
int x,y,s;
};
queue<node>q;
int T,n,sx,sy,ex,ey;
int b[111][111];
int dx[8] = {1,1,-1,-1,2,2,-2,-2},dy[8]={2,-2,2,-2,1,-1,1,-1};
int main( ){
cin>>T;
while(T--){
while(!q.empty( ))q.pop( );
q.pop( );
cin>>n>>sx>>sy>>ex>>ey;
memset(b,0,sizeof(b));
node a;
a.x=sx,a.y=sy,a.s=0;
q.push(a);
b[sx][sy]=1;
do{
int f=0;
a=q.front( );
if(a.x==ex&&a.y==ey){
cout<<a.s<<endl;
f = 1;
}
if(f) break;
for(int v = 0; v < 8; v++){
int nx = a.x + dx[v] , ny = a.y + dy[v];
if(!b[nx][ny] && nx < n && nx >= 0 && ny < n && ny >= 0){
node c;
c.x = nx , c.y = ny , c.s = a.s + 1;
q.push(c);
b[nx][ny] = 1;
}
}
q.pop();
}while(!q.empty());
}
}

总结

bfs常规思路:

我们通常是通过答案建树,然后bfs遍历这棵树,找到目标就输出,根据bfs的性质,此时一定是最优的

双端队列剪枝:

双端队列,很显然,深度越深状态越多,状态越多时间复杂度越大,双端队列也是靠这个实现的

如果我们同时知道目标和起点,那我们可以通过分别对目标,起点进行bfs遍历,找到共同点就返回答案,达到剪枝效果

浅谈bfs的更多相关文章

  1. 浅谈DFS,BFS,IDFS,A*等算法

    搜索是编程的基础,是必须掌握的技能.--王主任 搜索分为盲目搜索和启发搜索 下面列举OI常用的盲目搜索: 1.dijkstra 2.SPFA 3.bfs 4.dfs 5.双向bfs 6.迭代加深搜索( ...

  2. 虚拟化构建二分图(BZOJ2080 题解+浅谈几道双栈排序思想的题)

    虚拟化构建二分图 ------BZOJ2080 题解+浅谈几道双栈排序思想的题 本题的题解在最下面↓↓↓ 不得不说,第一次接触类似于双栈排序的这种题,是在BZOJ的五月月赛上. [BZOJ4881][ ...

  3. 浅谈 Fragment 生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...

  4. 浅谈 LayoutInflater

    浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...

  5. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

  6. 浅谈SQL注入风险 - 一个Login拿下Server

    前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...

  7. 浅谈WebService的版本兼容性设计

    在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...

  8. 浅谈angular2+ionic2

    浅谈angular2+ionic2   前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别.   1. 项目所用:angular2+ionic2 ...

  9. iOS开发之浅谈MVVM的架构设计与团队协作

    今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

随机推荐

  1. Java实现 LeetCode 731 我的日程安排表 II(二叉树)

    731. 我的日程安排表 II 实现一个 MyCalendar 类来存放你的日程安排.如果要添加的时间内不会导致三重预订时,则可以存储这个新的日程安排. MyCalendar 有一个 book(int ...

  2. Java实现 LeetCode 28 实现strStr()

    28. 实现 strStr() 实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 ...

  3. java实现蓝桥杯约瑟夫环

    n 个人的编号是 1~n,如果他们依编号按顺时针排成一个圆圈,从编号是1的人开始顺时针报数. (报数是从1报起)当报到 k 的时候,这个人就退出游戏圈.下一个人重新从1开始报数. 求最后剩下的人的编号 ...

  4. Java实现 蓝桥杯 历届试题 城市建设

    问题描述 栋栋居住在一个繁华的C市中,然而,这个城市的道路大都年久失修.市长准备重新修一些路以方便市民,于是找到了栋栋,希望栋栋能帮助他. C市中有n个比较重要的地点,市长希望这些地点重点被考虑.现在 ...

  5. Java实现第九届蓝桥杯书号验证

    书号验证 2004年起,国际ISBN中心出版了<13位国际标准书号指南>. 原有10位书号前加978作为商品分类标识:校验规则也改变. 校验位的加权算法与10位ISBN的算法不同,具体算法 ...

  6. cuda 9.0

    https://docs.nvidia.com/cuda/archive/9.0/index.html cuda9.0工具包

  7. 分布式ID总结

    分布式ID 生成的ID使用场景 几乎所有的业务系统,都有生成一个记录标识的需求,例如:message_id, order_id.这个记录标识往往就是数据库中的唯一主键,数据库上会建立聚集索引(clus ...

  8. Python Opencv-contrib Camshift&kalman卡尔曼滤波&CSRT算法 目标跟踪实现

    本次课题实现目标跟踪一共用到了三个算法,分别是Camshift.Kalman.CSRT,基于Python语言的Tkinter模块实现GUI与接口设计,项目一共包含三个文件: main.py: # co ...

  9. sql server 取多条数据的最大值

    实列: SELECT a.BillDate '[开票时间]', a.Hdbh '[运单号]', a.Status '运单状态', a.DisplayStatus '运单状态字', b.name '开票 ...

  10. PIP设置镜像源

    PIP设置镜像源 pip安装Python包时候,默认是国外的下载源,速度太慢,本文介绍几种设置pip国内镜像源的方法 镜像源 阿里云 http://mirrors.aliyun.com/pypi/si ...