利用深度优先搜索算法和广度优先搜索算法解迷宫问题
来源:互联网 发布:java设置test字体大小 编辑:程序博客网 时间:2024/06/06 09:18
本来应该是在大一就该掌握的内容,我却迟迟没有去了解,最近比较闲,今天就好好讨论一下图搜索算法的两个分支,深度优先算法与广度优先算法。本篇博客将分别利用深度优先算法和广度优先算法解决迷宫问题。
所谓迷宫问题,这里我们用一个二维数组
map[5][5]={
0,1,0,0,1
0,0,0,0,0
1,0,0,0,1
0,1,0,0,0
}
来表示迷宫,1表示墙壁,0表示通路,问题就是要找出从左上角到右下角的一条最短通路。
我们先给出深度优先的解决办法,所谓深度优先搜索,在迷宫问题里就是不撞南墙不回头,能走得深一点就尽量深一点。如果碰到了墙壁就返回前一个位置尝试其他的方向。在《啊哈!算法》中作者给出了一个深度优先搜索的基本模型,笔者认为比较贴切。
这里给出dfs算法的常见套路,大部分算法都可以采用这种经典的模板。
void dfs(int step){ if( xxx == xxx) // 是否满足条件,满足后进行一定的处理,如输出,记录最小值等
{
....
}
for( i=0;i<n;i++) // 尝试每一种可能 { 各种条件约束; // 不满足可以直接continue
mark 下 i ,表示已经走过;
继续下一步 dfs(step+1);
还原 i ,继续下种可能; } }
下面就给出对应迷宫问题的dfs(depth first search)函数代码
char mark[5][5]; //用于记录走过的点int min = 26; //能抵达终点的最短步数int ways = 0; //走法数int dir[4][2] = { //右下左上四个方向 { 1,0 },{ 0,1 },{ -1,0 },{ 0,-1 }};void dfs(int step, int x, int y){ int i; int tx, ty; if (x == 4 && y == 4) { // 已经到达出口 if (step < min) min = step; ways++; return; } for (i = 0; i < 4; i++) { tx = x + dir[i][0]; ty = y + dir[i][1]; if (tx < 0 || tx>4 || ty < 0 || ty>4) // 判断是否碰到墙壁 continue; if (map[ty][tx] == 0 && mark[ty][tx] == 0) { // 判断是否碰到障碍物,或者已经走过 mark[ty][tx] = 1; //标记已到过此点 dfs(step + 1, tx, ty); //进行下一步尝试 mark[ty][tx] = 0; //尝试结束,取消对此点标记 } }}
可以在主函数调用dfs函数并打印走法数和最短步数。要特别注意在结束从某一点开始的扩展尝试后要取消对该点的标记,因为在深度搜索算法中一个点是可能被反复访问的,如果不取消之前走过路的标记的话,将无法遍历每一种走法,从而可能导致无法找出最优走法。很显然,深度优先算法的优点是能够快速找到一条通路,缺点是遍历所有可能的通路时效率不高。
广度搜索与深度搜索恰恰相反,如果说深度搜索是一条路走到黑的话,广度优先搜索就是层层推进,步步为营。简单来将,广度优先算法便是先找到所有距离出发点为1的所有点,然后在所有离出发点1步的点的基础上找到所有距出发点2步的所有点,以此类推,直到找到终点。
要实现广度优先搜索,我们需要用到队列这种数据结构,所谓队列就是先到先出,排头出列,排尾入列。我们可以用数组实现这种数据结构。另外我们还得考虑记录每个点的信息,包括点的坐标以及点离出发点步数。我们用一个结构体记录点的信息。
typedef struct{ int x; int y; int step;}pt;pt queue[25];int front = 0, rear = 0;void bfs(void){ int i; int tx, ty; int flag = 0; //flag判断是否找到终点 queue[rear].x = 0; //将出发点入队 queue[rear].y = 0; queue[rear].step = 0; rear++; while (front < rear) { //队列中还有元素的话 for (i = 0; i < 4; i++) { //遍历四个方向 tx = queue[front].x + dir[i][0]; ty = queue[front].y + dir[i][1]; if (tx < 0 || tx>4 || ty < 0 || ty>4) continue; if (map[ty][tx] == 0 && mark[ty][tx] == 0) { mark[ty][tx] = 1; queue[rear].x = tx; queue[rear].y = ty; queue[rear].step = queue[front].step + 1; rear++; } if (tx == 4 && ty == 4) { flag = 1; break; } } if (flag == 1) break; front++; } printf("%d\n", queue[rear - 1].step);}
这里的rear(队尾)指向队列尾端的下一位,这样的话我们将其初始化为0代表开始时队列为空。在广度优先搜索中每个点只经过一次,所以不能像深搜一样取消点的标记。深度优先与广度优先搜索算法虽然不难,但许多图算法都是基于其上的,笔者觉得很有了解的必要。
- 利用深度优先搜索算法和广度优先搜索算法解迷宫问题
- 深度优先搜索 广度优先搜索算法
- 【游戏编程】AI-迷宫寻路算法-深度优先搜索和广度优先搜索
- 【游戏编程】AI-迷宫寻路算法-深度优先搜索和广度优先搜索
- AI-迷宫寻路算法-深度优先搜索和广度优先搜索
- 算法之深度优先搜索和广度优先搜索
- 搜索算法-广度优先和深度优先搜索
- 算法二:深度和广度优先搜索
- 迷宫问题|深度优先搜索&广度优先搜索
- 深度优先,广度优先和迭代加深搜索算法
- 图的深度优先和广度优先搜索算法
- [算法] 基本图算法:深度优先搜索、广度优先搜索
- 算法:队列与广度优先搜索(迷宫问题)
- C++广度优先搜索算法之迷宫问题
- 深度优先搜索算法和广度优先搜索算法的搜索次序(二叉树)
- 算法导论-图的搜索算法之深度优先搜索和广度优先搜索
- 广度优先搜索算法
- 广度优先搜索算法
- 微信公众平台开发入门教程
- HDU-1233 还是畅通工程(prim)
- 幂运算
- 用C++可变参数模板实现类似C语言的printf
- nginx 自启动
- 利用深度优先搜索算法和广度优先搜索算法解迷宫问题
- Rhyme/ java TCP网络编程 聊天室(群聊与私聊)TCP、多线程、IO流编程完整代码实现
- SpringMVC详解
- strstr函数的用法
- 前端基础 css笔记
- Java多线程的6种状态
- Functional Interface- java8引入特性
- 利用栈对数据进行逆置操作
- java web 开发环境布置学习笔记1