bfs思想解决迷宫问题

宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。

光用语言描述起来可能不太理解,下面直接看一道关于bfs类似的题

1 int data[5][5]={
2     {0,1,0,0,0},
3     {0,1,0,1,0},
4     {0,0,0,0,0},
5     {0,1,1,1,0},
6     {0,0,0,1,0}
7 };

迷宫问题,首先0代表可以顺利通过,但是1代表墙壁,即无法通过
起始点是在(0 0),终点是在(4 4),请找出一条通路,并打印出其路径

由于这个题是需要打印出其路径,所以我们首先要定义一个pre是用来指向此刻路径的父亲路径,只有这样当我们找到(4,4)的时候,我们才可以凭借着其父亲路径将从起点到终点的路径输出出来

1、首先我们要定义一个结构体,结构体里面可以存储我们通过的路径,代码如下:

1 typedef struct sss
2 {
3     int x,y;
4     int pre;   //记录其父亲路径的位置
5 }qq;
6 qq queue[100];

2、其次由于在迷宫中摸索的时候是需要有方向的,所以我们还需要定义一个二维数组去指示下一步的方向,代码如下:

1 int dxy[4][2]={
2     {-1,0},{0,1},{1,0},{0,-1}
3 };     //(-1,0)就相当于是此刻的x坐标-1,y坐标不动,即是向上一个单位,(0,1),(1.0),(0,-1)也是同理

3、我们还要定义一个数组用来表示当前路径是否被访问过,代码如下:

1 int visit[5][5]={0};   //0代表未访问,1代表已访问

如果这几个都定义好了,其实也就没啥了,接下来就是整体代码环节了:

 1 #include <stdio.h>
 2 int data[5][5]={
 3     {0,1,0,0,0},
 4     {0,1,0,1,0},
 5     {0,0,0,0,0},
 6     {0,1,1,1,0},
 7     {0,0,0,1,0}
 8 };
 9 
10 typedef struct sss
11 {
12     int x,y;
13     int pre;
14 }qq;
15 qq queue[100];
16 int dxy[4][2]={
17     {-1,0},{0,1},{1,0},{0,-1}
18 };
19 int visit[5][5]={0};   //0代表未访问,1代表已访问
20 
21 void bfs(int s,int d);
22 void print_data(int rear);
23 bool cmp(int next_x,int next_y);
24 int main(int argc, char *argv[])
25 {
26     
27     bfs(0,0);
28     return 0;
29 }
30 
31 void bfs(int s,int d)
32 {
33     int front=0,rear=1;
34     int next_x,next_y;
35     int i;
36     queue[front].x=s;
37     queue[front].y=d;
38     queue[front].pre=-1;
39     visit[s][d]=1;
40 
41     while(front<rear)
42     {
43         for(i=0;i<4;i++)
44         {
45             next_x=queue[front].x+dxy[i][0];
46             next_y=queue[front].y+dxy[i][1];
47             if(cmp(next_x,next_y))
48             {
49                 queue[rear].x=next_x;
50                 queue[rear].y=next_y;
51                 queue[rear].pre=front;
52                 visit[next_x][next_y]=1;
53                 rear++;
54             }
55             else
56                 continue;
57 
58             if(next_x==4&&next_y==4)
59             {
60                 print_data(rear-1);
61             }
62         }
63         front++;
64     }
65     
66 }
67 
68 void print_data(int rear)
69 {
70     if(rear!=-1)
71     {
72         print_data(queue[rear].pre);
73         printf("(%d %d)\n",queue[rear].x,queue[rear].y);
74     }
75 }
76 
77 bool cmp(int next_x,int next_y)
78 {
79     if(next_x>=0&&next_x<5&&next_y>=0&&next_y<5&&visit[next_x][next_y]==0&&data[next_x][next_y]==0)
80         return true;
81     else
82         return false;
83 }

下面来分析一下代码的执行过程

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),终点在(4,4),现在让找到一条通路输出,首先由于(0,0)

是起点,所以我们应该将(0,0)放入到结构体数组queue[0]中,因为我们还需要找下一个邻接的next_x和next_y,所以我们应该定义一个指向当前的位置的front和指向下一个位置的rear,在初始时front=0,rear=1,,所以我们将(0,0)放入到结构体数组queue[0]中并设置为已经访问后,

数组下标 x y pre(父亲位置)
0 0 0 -1

 

然后找寻下一个节点,当我们执行for语句的时候即是在遍历当前位置的四个方向,找出满足条件的将其放入到结构体数组中,通过四个方向找完后发现只有next_x=1,next_y=0是满足条件的,在将其存入到数组中的时候要注意他的父亲位置是0也就是front,故将其存入数组并设置为已经访问后

数组下标 x y pre(父亲位置)
0 0 0 -1
1 1 0 0
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

此刻判断当前的位置是否到终点了,明显是没有到的,故rear++,front++,此时front=1,rear=2,此时要从(1,0)开始找邻接点了,同理当next_x=2,next_y=0时是符合条件的,将其装入数组并设置为已经访问后,

数组下标 x y pre(父亲位置)
0 0 0 -1
1 1 0 0
2 2 0 1
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

此时通过判断是没有到达终点的,所以front++,rear++,rear=3,front=2,此时通过找寻发现(2,1)和(3,0)都是符合的,所以都加入到数组中

数组下标 x y pre(父亲位置)
0 0 0 -1
1 1 0 0
2 2 0 1
3 2 1 2
4 3 0 2
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

此时判断依旧没有到达终点,则继续往下找,此时的front=3,rear=5,则开始从(2,1)继续往下找,则(2,2)是符合的,所以同理

数组下标 x y pre(父亲位置)
0 0 0 -1
1 1 0 0
2 2 0 1
3 2 1 2
4 3 0 2
5 2 2 3
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

此时的front=4,rear=6,则开始从(3,0)开始找起,(4,0)是符合条件的,所以同理

数组下标 x y pre(父亲位置)
0 0 0 -1
1 1 0 0
2 2 0 1
3 2 1 2
4 3 0 2
5 2 2 3
6 4 0 4

依次找下去即可,这里就不一步一步了,相信看到这里,您应该都懂了,希望着篇文章能对您有帮助,谢谢

 

上一篇:[究极好题][二分][bfs][二维前缀和]危险任务


下一篇:五 Java方法