广搜(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 773 滑动谜题(BFS)

    773. 滑动谜题 在一个 2 x 3 的板上(board)有 5 块砖瓦,用数字 1~5 来表示, 以及一块空缺用 0 来表示. 一次移动定义为选择 0 与一个相邻的数字(上下左右)进行交换. 最终 ...

  2. Java实现 蓝桥杯 算法训练 求和求平均值

    试题 算法训练 求和求平均值 问题描述 从键盘输入10个浮点数,求出它们的和以及平均值,要求用函数实现 输入格式 测试数据的输入一定会满足的格式. 1 10 (1行10列的向量) 输出格式 要求用户的 ...

  3. Java实现 LeetCode 283 移动零

    283. 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必 ...

  4. Java实现 LeetCode 240 搜索二维矩阵 II(二)

    240. 搜索二维矩阵 II 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target.该矩阵具有以下特性: 每行的元素从左到右升序排列. 每列的元素从上到下升序排列. ...

  5. Java实现 LeetCode 146 LRU缓存机制

    146. LRU缓存机制 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key) - ...

  6. 使用Pycharm安装插件时发生错误

    报错内容:pip._vendor.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.o ...

  7. Android Button的四种点击事件

    bta1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.m ...

  8. java实现第二届蓝桥杯地铁换乘(C++)

    地铁换乘. 为解决交通难题,某城市修建了若干条交错的地铁线路,线路名及其所属站名如stations.txt所示. 线1 苹果园 .... 四惠东 线2 西直门 车公庄 .... 建国门 线4 .... ...

  9. 钻进 Linux 内核看个究竟

    Linux 内核,这个经常听见,却不不知道它具体是干嘛的东西,是不是觉得非常神秘? Linux 内核看不见摸不着,而对于这类东西,我们经常无从下手.本文就以浅显易懂的语言,带你钻进 Linux 内核, ...

  10. Linux内核配置编译及基本调试方法

    一.Linux内核配置编译 1. 交叉编译设置:make ARCH=arm CROSS_COMPILE=arm-linux- 注:也可以直接修改顶层Makefile ARCH ?= arm CROSS ...