您的位置:首页 > 其它

广度优先搜索——BFS遍历

2017-02-12 20:53 519 查看
 广度优先搜索(Breadth First Search , BFS)是一个分层搜索的过程,没有回退过程,是非递归的。

为避免重复访问,需要一个状态数组visited
来存储各顶点的访问状态。为实现逐层访问,bfs算法在实现时需要一个队列,以记忆正在访问的这一层和上一层的顶点,以便于向下一层访问。

例题(1):营救(rescue)

输入描述:"."  :道路  "r" :Angle的朋友 "#" :墙壁  "x" :警卫

分析:本题要求从r位置出发到达Angel所在的位置且所需时间最少,适合bfs求解。但在本题中,步数最少的解不一定是最优解。

为求出最优解,采用如下的思路进行bfs搜索。

(1)将Angel的朋友到达某个方格的状态用一个结构体point表示,该结构体包含了Angel的朋友到达该方格时所走过的步数及所花费的时间;在bfs搜索中,队列中的结点是point型数据.

(2)定义一个二维数组mintime,mintime[i][j]表示Angel的朋友走到(i,j)位置所需的最少时间;在bfs搜索过程中,从当前位置走到相邻的位置(x,y)时,只有当该种走法比走到(x,y)所需的时间更少时,才会把当前走到(x,y)位置的状态入队列,否则是不会入队列的。

(3)不能一判断出到达目标位置就退出bfs过程,否则求出的最小时间仅仅是从r到达a最小步数的若干方案中的最小时间,不一定是最优解,一定要等到队列为空,才能得出结论。

另外在题目中未使用visited
数组,因为只有当下一个位置比上一个所需的时间少才能入队列,所以到达(x,y)的最少时间肯定是有下界的。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define maxint 0x3f3f3f3f
#define MAXN 200
using namespace std;
struct point
{
int x,y;
int step;
int time;
};
queue<point>Q;
int n,m;
char map[MAXN][MAXN];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int mintime[MAXN][MAXN];
int ax,ay;///Angel所在的位置
int bfs(point s);
int main()
{
int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(mintime,maxint,sizeof(mintime));
memset(map,0,sizeof(map));
for(i=0;i<n;i++)
scanf("%s",map[i]);
int sx,sy;
point start;
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
if(map[i][j]=='a'){ax=i,ay=j;}
else if(map[i][j]=='r'){sx=i,sy=j;}
}
start.x=sx;
start.y=sy;
start.step=0;
start.time=0;
mintime[sx][sy]=0;
int mint=bfs(start);
if(mint<maxint)
printf("%d\n",mint);
else
printf("can not arrived\n");
}
return 0;
}
int bfs(point s)
{
int i,j;
Q.push(s);
point hd;///队列头的位置
while(!Q.empty())
{
hd=Q.front();
Q.pop();
for(i=0;i<4;i++)
{
int x=hd.x+dir[i][0];
int y=hd.y+dir[i][1];
if(x>=0&&y>=0&&x<=n-1&&y
4000
<=m-1&&map[x][y]!='#')
{
point t;
t.x=x;
t.y=y;
t.step=hd.step+1;
t.time=hd.time+1;
if(map[x][y]=='x') t.time++;///杀死警卫的时间
///如果比最少时间少,则将t入队列
if(t.time<mintime[x][y])
{
mintime[x][y]=t.time;
Q.push(t);
}
}
}
}
return mintime[ax][ay];
}
广度优先搜索的伪代码

(1)若用邻接表存储图

dfs(顶点i)
{
visited[i]=1;
将顶点i入队列;
while(队列不为空)
{
取出队列头的顶点,设为k;
p=顶点k的边链表表头指针;
while(p不为空)
{
///设指针p指向的边结点所表示的边的另一个顶点为j;
if(顶点j未访问过)
{
将顶点j标记为访问;
将顶点j入队列;
}
p=p->next;
}
}
}


(2)用邻接矩阵存储图

dfs(顶点i)
{
visited[i]=1;
将顶点i入队列;
while(队列不为空)
{
取出队列头的顶点,设为k;
for(j=0;j<n;j++)
{
///j是k的邻接点,且未被访问过
if(map[k][j]==1&&!visited[j])
{
将顶点j标记为访问;
将顶点j入队列;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: