一些BFS参考的博客:

https://blog.csdn.net/ldx19980108/article/details/78641127

https://blog.csdn.net/u011437229/article/details/53188837

https://blog.csdn.net/m0_37316917/article/details/70879977

关于queue头文件常用函数的解释:

https://www.cnblogs.com/xuning/p/3321733.html

具体内容等做到了慢慢写,现在还在研究queue

迷宫问题

定义一个二维数组:

int maze[5][5] = {

0, 1, 0, 0, 0,

0, 1, 0, 1, 0,

0, 0, 0, 0, 0,

0, 1, 1, 1, 0,

0, 0, 0, 1, 0,

};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

Input

一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

Output

左上角到右下角的最短路径,格式如样例所示。

Sample Input

0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

Sample Output

(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <stack>
#include <queue>
using namespace std;
/*做这题有了很多新感悟,如果是要探求一共有几种解法的话,那么我应该使用DFS算法,
但要是求最短路径的话,BFS算法是按层算的,所以它能更容易算出最短路径*/
/*这道题有个令人舒服的操作就是讲队尾的数据不断抽出(因为有个指针不断指向父节点)
然后放入堆栈中,再一个个从堆栈顶部抽出,所以我最后得出的数据要是最后的指针*/
int map[][], newx[]={-,,,}, newy[]={,,-,};
bool sign[][];
class location
{
public:
int x,y;//坐标
location* father;//指向父节点的位置
}; location* bfs()
{
int x, y;
queue<location*> Q;//建立关于location指针的队列
location* begin = new location();//【重要】这里需要new一个空间来放置新数据
begin->x = ; begin->y = ; begin->father = NULL;
//初始化起点,其父节点为空,要放在函数内创建队列【重要】
Q.push(begin);//放入队列的第一个点
while ( !Q.empty() )//这里是队列和堆栈常用的判断方式,若为空队列则返回1
{
location* linshi = Q.front();
Q.pop();//获得第一个地址后就可以将它从队列里拉出来了
for ( int i= ; i< ; i++ )//开始了哦,四方遍历
{
x = linshi->x + newx[i];
y = linshi->y + newy[i];
if ( x< || x> || y< || y> ) continue;
//超出边界,判断下一个点吧
if ( sign[x][y] == true ) continue;
//如果这个点已经走过了,我也不会再回头
if ( map[x][y] == ) continue;
//如果有墙壁的话,我当然不会傻傻撞上去的啦
//经过上面的三连判断,终于,这个点是可以走过去的
location* NEW = new location();
NEW->x = x; NEW->y = y; NEW->father = linshi;
//建立一个新指针,将这个可行点代入数值
if ( x== && y== ) return NEW;
//已经达到终点了哦,把这个地址带回去吧
Q.push(NEW);//不满足上面这个条件呀,那就将这个点放入队列之中吧
sign[x][y] = true;//本点到此一游,来过了哦
}
}
} int main()
{
for(int i=;i<=;i++)
{
for(int j=;j<=;j++)
{
cin>>map[i][j];//初始化迷宫
sign[i][j]=false;//重置sign数组
}
}
location* p=bfs();//将最后得到的地址赋给p
stack<location*> S;
while ( p != NULL )//只要指针不为空的话
{
S.push(p);
p = p->father;
}
while( !S.empty() )//只要堆栈不为空的话
{
location* temp = S.top();//依旧是新建一个指针,其等于堆顶的地址
S.pop();//【得到它的信息便可以删除啦】
cout<< "(" << temp->x- << ", " << temp->y- << ")" <<endl;
}
return ;
}

这些代码的灵感很多来自于下面的代码,【】中做的是我的注释

#include<iostream>
#include<queue>
#include<stack>
using namespace std;
int migong[][];//保存迷宫图
bool flag[][];//标记改点是否到达过
class Stat
{
public:
int x,y;
int t;
Stat* father;//指向其父状态,用于逆向寻找路径
};
int R[][]={
-,,
,,
,-,
,
};//用于状态扩展
Stat* BFS()//返回终点状态
{
queue<Stat*> Q;//用于存储还没有被扩展的(即将扩展)状态//【指向这个位置】
int x=,y=,t=;
Stat* start = new Stat();//这里是我栽过大坑,由于是在函数内部定义的对象,必须要用new来分配内存与堆中
start->x=start->y=;//【start的位置为(0,0)】
start->t = ;
start->father = NULL;//开始状态没有父状态
//【上面这几句话是初始点的初始化】
Q.push(start);//【这里是放入第一个点的意思】
while( Q.empty() == false )//直到搜索完所有状态退出循环
{
Stat* temp = Q.front();//【新建一个临时的指针指向队头】
Q.pop();//【删除队头,虽然是删除队头,但是这个指针本身并未消失,只是被移出】
for(int i=;i<;i++)//这里就是状态的扩展,向上下左右四个方向扩展
{
x = temp->x + R[i][];
y = temp->y + R[i][];
if(x<||y<||x>||y>)//超出边界,便直接舍弃该状态
continue;
if(flag[x][y] == true)//到达过该状态,也直接舍弃
continue;
if(migong[x][y] == )//没有路,也直接舍弃
continue;
//【上面这三连判断的代码很酷,很对我口味】
Stat* tempS = new Stat();//创建新状态
tempS->x = x;
tempS->y = y;
tempS->t = temp->t+;//时间加一
tempS->father = temp;//指向父节点
//【上面这段作用主要是将可行点放入队列中】
if( x == && y == )
{
return tempS;//搜索到了终点,便返回
}
Q.push(tempS);//将新状态加入队列中
flag[x][y] = true;//标记该状态已经到达过
}
//【这段for循环后,刚开始进入的点的所有可能性都放入队列中,准备进入下一
//个阶段,继续检索这个队列】
}
return start;
} int main()
{
for(int i=;i<;i++)//循环输入迷宫
{
for(int j=;j<;j++)
{
cin>>migong[i][j];
flag[i][j] = false;//全部重置为未标记
}
}
Stat* p = BFS();
stack<Stat*> S;//声明堆栈S
//放入栈中,主要是为了让其反序,不然从目标状态找其父节点遍历的话,是反的
//【这个想法很好,不这么做的话从队列里先出来的是终点】
while(p != NULL)//
{
S.push(p);
p = p->father;
}
while(S.empty() == false)
{
Stat* temp = S.top();
S.pop();//【得到它的信息便可以删除啦】
cout<< "(" << temp->x << "," << temp->y << ")" <<endl;
}
}

Rescue

Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the prison.

Angel's friends want to save Angel. Their task is: approach Angel. We assume that "approach Angel" is to get to the position where Angel stays. When there's a guard in the grid, we must kill him (or her?) to move into the grid. We assume that we moving up, down, right, left takes us 1 unit time, and killing a guard takes 1 unit time, too. And we are strong enough to kill all the guards.

You have to calculate the minimal time to approach Angel. (We can move only UP, DOWN, LEFT and RIGHT, to the neighbor grid within bound, of course.)

InputFirst line contains two integers stand for N and M.

Then N lines follows, every line has M characters. "." stands for road, "a" stands for Angel, and "r" stands for each of Angel's friend.

Process to the end of the file. 
OutputFor each test case, your program should output a single integer, standing for the minimal time needed. If such a number does no exist, you should output a line containing "Poor ANGEL has to stay in the prison all his life." 
Sample Input

7 8
#.#####.
#.a#..r.
#..#x...
..#..#.#
#...##..
.#......
........

Sample Output

13
/*#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
using namespace std;*/
/*这道题想法肯定是要BFS,但我不是很清楚大小顶堆会被用在哪里*/
/*貌似有点想法了,因为杀死卫兵需要多花一秒的时间,所以要BFS出所有的点,再提取出
那个步数最少的位置,因为如果是步数加一的话,我就不能将其马上加入队列中了,必须将
这个步数放到下一层的队列中,这样才算是公平公正*/
/*太难了= =我考虑的东西真的太少了,这个BFS和其他的BFS相比,就是标记步数的时候不
一定要继续标记,因为有卫兵的存在,卫兵还是被拉入下一步考虑的好,因为它和其他的点
不是同等级的运算*/
/*int n, m, step[205][205], newx[4]={-1,1,0,0}, newy[4]={0,0,-1,1}, x2, y2;
char map[205][205]; struct location
{
int x, y, steps;
friend bool operator > ( location a, location b)
{
return a.steps > b.steps;
}
} temp, linshi; priority_queue< location , vector<location> , greater<location> > S;
//用来计算到达终点路线的步数 void BFS(int xx , int yy)
{
int x, y, i, j, steps;
memset( step , 0 , sizeof(step) );
queue<location> Q;//用来BFS的普通队列
step[xx][yy]=1;
temp.x = xx; temp.y = yy; temp.steps = 1;
Q.push(temp);
while ( !Q.empty() )
{
temp = Q.front();
Q.pop();
for ( i=0 ; i<4 ; i++ )
{
x = temp.x + newx[i];
y = temp.y + newy[i];
steps = temp.steps + 1;
if ( x>n || x<1 || y>m || y<1 ) continue;//越界,告辞!
if ( map[x][y] != 'a' )
{
if ( map[x][y] == '#' ) continue; //撞墙,告辞!
if ( step[x][y] != 0 ) continue;//用过,告辞!
if ( map[x][y] == 'x' ) steps+=1;//有怪自增一
}
linshi.x = x; linshi.y = y; linshi.steps = steps;
step[x][y] = steps;
if ( map[x][y] != 'a' ) Q.push(linshi);
//cout<<linshi.x<<' '<<linshi.y<<endl;
if ( map[x][y] == 'a' ) S.push(linshi);
}
}
/*for ( i=1 ; i<=n ; i++ )
{
for ( j=1 ; j<=m ; j++ )
{
printf("%d ", step[i][j]);
}
cout<<endl;
}
return;
} int main(void)
{
int i, j, beginx, beginy;
while ( scanf("%d%d", &n, &m) != EOF )
{
getchar();
for ( i=1 ; i<=n ; i++ )
{
for ( j=1 ; j<=m ; j++ )
{
scanf("%c", &map[i][j] );
if ( map[i][j] == 'r' )
{
beginx=i;
beginy=j;
}
if ( map[i][j] == 'a' )
{
x2=i;
y2=j;
}
}
getchar();
}
while ( !S.empty() ) S.pop();
BFS(beginx, beginy);
if ( !S.empty() ) printf("%d\n", S.top().steps-1 );
else printf("Poor ANGEL has to stay in the prison all his life.\n");
}
return 0;
}*/
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std; struct node
{
int x,y,step;
friend bool operator < (node n1,node n2)
{
return n1.step > n2.step;
//尽管下面是大顶堆的格式,但这里转换成小顶堆
}
}; int n,m,vis[][];
char map[][];
int x1,x2,y1,y2;
int to[][] = {,,-,,,,,-}; int bfs()
{
int i;
priority_queue<node> Q;//顶堆声明
//将步数最少的放在优先处理,不用像我一样放在一起比较
node a,next;//临时数据声明
a.x = x1;
a.y = y1;
a.step = ;
Q.push(a);
vis[x1][y1] = ;
while( !Q.empty() )
{
a = Q.top();
Q.pop();
if( a.x == x2 && a.y == y2 ) return a.step;
for(i = ; i<; i++)
{
next = a;
next.x += to[i][];
next.y += to[i][];
if(next.x< || next.y< || next.x>=n || next.y>=m || !vis[next.x][next.y] || map[next.x][next.y] == '#') continue;
next.step++;
if( map[next.x][next.y] == 'x')//卫兵处多花费了一秒
next.step++;
if( next.step <= vis[next.x][next.y] )//存入最小时间
{
vis[next.x][next.y] = next.step;
Q.push(next);
//时间要尽量小,否则就不要存进来了
}
}
}
return ;
} int main()
{
int i,j;
while( scanf("%d%d",&n,&m) != EOF )
{
for(i = ; i < n; i++)
{
scanf("%s",map[i]);
for(j = ; map[i][j]; j++)
{
if(map[i][j] == 'r')
{
x1 = i;
y1 = j;
}
else if(map[i][j] == 'a')
{
x2 = i;
y2 = j;
}
}
}
memset( vis , , sizeof(vis) );
int ans = ;
ans = bfs();
if(ans)
printf("%d\n",ans);
else
printf("Poor ANGEL has to stay in the prison all his life.\n");
} return ;
}

【2018.07.30】(广度优先搜索算法/队列)学习BFS算法小记的更多相关文章

  1. 【2018.07.29】(深度优先搜索/回溯)学习DFS算法小记

    参考网站:https://blog.csdn.net/ldx19980108/article/details/76324307 这个网站里有动态图给我们体现BFS和DFS的区别:https://www ...

  2. 【2018.07.28】(字符串/回文串)学习Manacher算法小记

    主要是应用在回文串啦,原理也理解了老半天,如果没有图片的话,我也看不太懂它的原理 学习的灵感来源来自于:https://segmentfault.com/a/1190000008484167 /* 最 ...

  3. 【2018.07.27】(字符串/找相同)学习KMP算法小记

    虽然说原理很好理解,但是代码理解了花费我一个下午的时间,脑阔痛 该注释的地方都标记了,希望以后看到这些代码我还能好好理解吧 学习的链接地址:https://www.cnblogs.com/teble/ ...

  4. 2018.07.30 cogs2632. [HZOI 2016] 数列操作d(线段树)

    传送门 线段树基本操作 区间加等差数列,维护区间和. 对于每个区间维护等差数列首项和公差,易证这两个东西都是可合并的,然后使用小学奥数的知识就可以切掉这题. 代码: #include<bits/ ...

  5. 2018.07.30 bzoj4355: Play with sequence(线段树)

    传送门 维护区间覆盖成非负数,区间变成max(xi+a,0)" role="presentation" style="position: relative;&q ...

  6. python 递归深度优先搜索与广度优先搜索算法模拟实现

    一.递归原理小案例分析 (1)# 概述 递归:即一个函数调用了自身,即实现了递归 凡是循环能做到的事,递归一般都能做到! (2)# 写递归的过程 1.写出临界条件2.找出这一次和上一次关系3.假设当前 ...

  7. Day1 BFS算法的学习和训练

    ​ 因为自己的原因,之前没有坚持做算法的相应学习,总是觉得太难就半途而废,真的算是一个遗憾了,所以现在开始,定一个30天入门学习算法计划. ​ 我是根据<算法图解>的顺序进行安排的,自己对 ...

  8. python 递归,深度优先搜索与广度优先搜索算法模拟实现

    一.递归原理小案例分析 (1)# 概述 递归:即一个函数调用了自身,即实现了递归 凡是循环能做到的事,递归一般都能做到! (2)# 写递归的过程 1.写出临界条件 2.找出这一次和上一次关系 3.假设 ...

  9. 广度优先搜索 BFS算法

    广度优先搜索算法(Breadth-First-Search,BFS),又称作宽度优先搜索.BFS算法是从根节点开始,沿着树的宽度遍历树的节点.如果所有节点均被访问,则算法中止. 算法思想 1.首先将根 ...

随机推荐

  1. iview的table中Tooltip的使用

    这篇文章主要介绍了iview-admin中在table中使用Tooltip提示效果. 1. table中文字溢出隐藏,提示气泡展示所有信息 jLongText(item){ item.render = ...

  2. 90% 的 Python 开发者不知道的描述符应用

    经过上面的讲解,我们已经知道如何定义描述符,且明白了描述符是如何工作的. 正常人所见过的描述符的用法就是上篇文章提到的那些,我想说的是那只是描述符协议最常见的应用之一,或许你还不知道,其实有很多 Py ...

  3. 苹果appstore应用名下面的开发者名称填写或修改

    最近上架不小心遇到一个问题,开发者名称写错了,放假前大意了,记录一下修改过程,希望碰到同样问题的伙伴不要要着急,下面的内容可能帮你哦. 我们应用的之前的开发者名称是个人的,之前没注意这个问题,以后想注 ...

  4. ElementUI动态表格数据转换formatter

    elementUI的表格初始化比较简单,声明prop值对应的字段名即可. 而在实际应用中,我们常常有这种需求:从服务器获取的数据并不是我们要显示的最终结果,涉及一些状态.类型.日期时间等的转换,这时候 ...

  5. VSCode Git 没有活动的源代码控制提供程序

    主要原因:我以前安装的Git只允许在Git-Bash中运行,需要重新安装Git,选择允许三方软件的那个选项,然后安装Git插件,修改git.path即可. 以下是解决过程中的尝试,记录如下,实际上只需 ...

  6. HTML基础之HTML常用标签

    下面小编为大家整理一些HTML的常用标签 a.布局标签 div标签定义文档中的分区或节(division/section),可以把文档分割为独立的.不同的部分,主要用于布局. aside标签的内容可用 ...

  7. Visual Studio(Year)编辑器调试在IIS发布的Web程序出现错误的解决

    如下图所示:

  8. archlinux 蓝牙耳机没有声音

    前提 蓝牙已开,并且连接成功,但是蓝牙耳机没有声音. 安装 pacman -S pulseaudio-bluetooth pulsemixer 切换设备输出为蓝牙耳机

  9. redis中对list类型某个元素的查找和删除

    我们的信息都是放到redis的缓存中,结构为list,如果知道特定的值的话,通过LREM  key  count  value这样就可以.对于redis的list结构,获取某个位置的值通过 LINDE ...

  10. Spring Cloud 功能使用的层面组件(一)

    来源:赤峰seo 实际上,Spring Cloud 是一个全家桶式的技术栈,它包含了很多组件.本文先从最核心的几个组件,也就是 Eureka.Ribbon.Feign.Hystrix.Zuul 入手 ...