BFS(不保留路径和保留路径)以及queue函数常见的用法
一:queue函数
-
1 什么是queue函数
首先介绍一下什么是queue函数以及队列:
队列就好比是等绿灯前的汽车,先来的就在前面排好队,后来的汽车就排在后面。很明显,当亮绿灯时,先进来的车先走,后来的后走。队列也是如此,先进入队列的先出去,满足先进先出原则。
我们先来看一张图(来自百度)
我们可以看到队列的进出方向,它的用法在下面的代码里面 -
2.queue函数的用法
#include<iostream>
#include<cstdio>
#include<queue>//预定义里面包含queue函数
typedef struct node
{
int x;
int y;
}Node;//构造一个结构体
int main()
{
queue<int> q ;//创建一个int类型的队列,queue<类型>;
queue<struct node> p;//创建一个自己定义的结构体类型的队列;
int a=0;
int k;
q.push(a);//将a放入队列q的末尾;
k=q.front();//返回出q队列的第一个的值,赋值给k,此时是没有出队列的;
k=q.back();//返回出q队列的最后一个的值,赋值给k,此时也是没有出队列;
q.pop();//将q队列的第一个出队列,但是不能返回其值;
k=q.empty();//判断队列q是否为空,是就返回true(1),否就返回false(0);
k=q.size();//返回队列q的长度,也就是队列中保留的个数;
Node t;
t.x=1;
t.y=1;
p.push(t);//进入队列前先给结构体赋值,不能进入后赋值;其他用法的话队列p与队列q一样;
return 0;
}
了解了queue函数,下面就是真正的运用了;
二:BFS(不保留路径)
我们用一个题目来了解一下
题目:Knight Moves
背景
萨穆罗洛夫先生,确实是一位了不起的棋手,他声称除了他之外,没有人能这么快地把骑士从一个位置移到另一个位置。你能打败他吗?
问题
你的任务是编写一个程序来计算骑士从一个点到达另一个点所需的最少移动次数,这样你就有机会比索穆罗洛夫更快。 对于不熟悉象棋的人,可能的骑士移动如图1所示。
输入
输入以单行上的方案数n开始。
接下来是N个场景。每个场景由包含整数的三行组成。第一行指定棋盘边的长度L(4<=L<=300)。整个棋盘的大小为LL。第二和第三行包含一对整数{0,…,L-1}{0,…,L-1},指定骑士在棋盘上的起始和结束位置。整数由一个空格分隔。您可以假设这些位置是该场景棋盘上的有效位置。
输出
对于输入的每个场景,您必须计算从起点移动到终点所需的最少骑士移动量。如果起点和终点相等,则距离为零。距离必须写在一行上。
测试样列:
Sample Input
3
8
0 0
7 0
100
0 0
30 50
10
1 1
1 1
Sample Output
5
28
0
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
void bfs();
typedef struct node
{
int x;
int y;
int temp;
}Node;
int x1[]={1,2,-1,-2,1,2,-1,-2};
int y1[]={2,1,2,1,-2,-1,-2,-1};
int m,sx,sy,ex,ey;
int visit[310][310];
int main()
{
int n;
cin>>n;
while(n--)
{
cin>>m>>sx>>sy>>ex>>ey;
if(sy==ey&&sx==ex)
printf("0\n");
else
bfs();
}
return 0;
}
void bfs()
{
queue<struct node> a;
Node s,t;
memset(visit,0,sizeof(visit));
int vx,vy,i;
s.temp=0;
s.x=sx;
s.y=sy;
a.push(s);
visit[sx][sy]=1;
while(!a.empty())
{
s=a.front();
a.pop();
for(i=0;i<8;i++)
{
vx=s.x+x1[i];
vy=s.y+y1[i];
if(vx<m&&vy<m&&vx>=0&&vy>=0&&!visit[vx][vy])
{
if(vx==ex&&vy==ey)
{
printf("%d\n",s.temp+1);
return;
}
else
{
t.x=vx;
t.y=vy;
t.temp=s.temp+1;
a.push(t);
visit[vx][vy]=1;
}
}
}
}
}
提取了模板出来
代码核心:
void bfs()
{
queue<struct node> q;
int visit[N][N];//判断是否访问过此点
memset(visit,0,sizeof(visit));
Node k,t;
int vx,vy,i;
k.x=sx;//sx,sy为开始的位置;
k.y=sy;
q.push(k);
while(!empty())
{
k=q.front();
q.pop();//取出了队列首元素,出队列
for(i=0;i<4;i++)
{
vx=k.x+xx[i];
vy=k.y+yy[i];
if(vx==ex&&vy==ey)//ex,ey为要发现的位置
{
printf("YES");
return;
}
if(.....判断是否满足入队条件&&!visit[vx][vy])//visit[][]是使每个点都只访问一次;
{
t.x=vx;
t.y=vy;
q.push(t);//存下位置,入队;
}
}
}
printf(“NO”);//队列为空,访问完所有点未找到;
}
二维数组的BFS都可以套用此模板,三维数组BFS和线性BFS可以关注我,我的博客里面有
三:BFS(保留路径)
题目:迷宫
定义一个二维数组:
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表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
输入
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
输出
左上角到右下角的最短路径,格式如样例所示。
样例输入
copy
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
样例输出
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
- 1.queue队列链表形式
分析:因为BFS一个点有多个后继点,但一个点只有一个前继点。我们将指针指向上一个点,通过从终点搜向起点,再输出的形式将路径整理出来。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
void bfs();
typedef struct node
{
int x;
int y;
struct node *last;
}Node;//*last指向上一个路径;
int map[6][6];//地图;
int visit[6][6];//是否访问地图中的点,没有访问为0,否则为1;
int x1[]={0,-1,0,1};
int y1[]={1,0,-1,0};
int main()
{
memset(visit,0,sizeof(visit));
int i,j;
for(i=0;i<5;i++)
{
for(j=0;j<5;j++)
{
cin>>map[i][j];
}
}
bfs();
return 0;
}
void bfs()
{
queue<struct node *> q;//queue的类型为指针类型
Node *ex;
ex=new Node;
ex->x=4;
ex->y=4;
ex->last=NULL;//设置出口
q.push(ex);
visit[4][4]=1;
int i,vx,vy;
while(!q.empty())
{
ex=q.front();
q.pop();
for(i=0;i<4;i++)
{
vx=ex->x+x1[i];
vy=ex->y+y1[i];
if(vx>=0&&vx<5&&vy>=0&&vy<5&&!visit[vx][vy]&&!map[vx][vy])
{
Node *t;
t=new Node;
t->x=vx;
t->y=vy;
t->last=ex;
visit[vx][vy]=1;
q.push(t);
if(vx==0&&vy==0)//搜索到起点
{
Node *p;
p=new Node;
p->last=t;
t=t->last;
while(t!=NULL)
{
printf("(%d, %d)\n",p->x,p->y);
p=t;
t=t->last;
}
printf("(%d, %d)",p->x,p->y);//输出最后的终点;
return;
}
}
}
}
}
- 2.自己构造队列,不用queue
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 10005
using namespace std;
int map[6][6];
int visit[6][6];
int queue[N]; //保留队列点的父点;
int xx[]={0,0,-1,1};
int yy[]={1,-1,0,0};
struct node
{
int x;
int y;
}f[N];
void bfs();
void print(int);
int main()
{
int i,j;
for(i=0;i<5;i++)
{
for(j=0;j<5;j++)
{
cin>>map[i][j];
}
}
bfs();
return 0;
}
void bfs()
{
int head,tail;//首尾的点分别用来记录队列中的位置,head为前点,tail为此点附近要入队列的点;
int vx,vy,i;
memset(visit,0,sizeof(visit));
head=-1;//输出队列时的出口;
tail=0;//刚开始从0位置入队列;
f[tail].x=4;
f[tail].y=4;
queue[tail]=head;
tail++;
while(head<tail)
{
head++;//输出队列的首点
for(i=0;i<4;i++)
{
vx=f[head].x+xx[i];
vy=f[head].y+yy[i];
if(vx<5&&vy<5&&vx>=0&&vy>=0&&!visit[vx][vy]&&!map[vx][vy])
{
f[tail].x=vx;
f[tail].y=vy;
visit[vx][vy]=1;
queue[tail]=head;//保留进入队列点的父点(从父点开始的搜索);
tail++;//进入队列的尾点
}
if(vx==0&&vy==0)
{
tail--;
print(tail);
return;
}
}
}
}
void print(int tail)
{
while(tail!=-1)
{
printf("(%d, %d)\n",f[tail].x,f[tail].y);
tail=queue[tail];
}
return;
}
因为本人是一个进阶阶段的小白,我的博客基本都会很详细的讲解关于一些算法以及一些竞赛题。
喜欢可以关注我,我会从小白的角度出发写的很详细,别的大佬没有get到的一些简单问题,我也尽量都写出来。想看关于三维数组BFS还有线性BFS,可以从我的博客中找到。