深搜和广搜 迷宫最短路径
2017-11-04 20:33
344 查看
一、概述
初次接触迷宫广搜问题,整了几天才渐渐明白其中原理;附上自己的学习经验(适合初学者);二、问题
输入:第一行输入一个整数,表示有几组数据; 第二行输入两个整数 行和列 (r ,c);接下来输入r行c列的矩阵(S是入口,E是出口,#代表墙,. 是可行区域)输出:从入口S到E的最短路径 (假设输入数据必定有一条可行路径)
例如:输入:
2 8 8 ######## #......# #.####.# #.####.# #.####.# #.####.# #...#..# #S#E#### 5 9 ######### #.#.#.#.# S.......E #.#.#.#.# #########
输出:
5 9
三、深搜
1、基本思想:运用递归回溯遍历整个迷宫,计算出所有可行路径,再比较出最短的;2、代码:
#include<stdio.h> #include<string.h> char a[100][100]; int dx[]={-1,0,1,0},dy[]={0,-1,0,1}; //定义出在当前位置走下一步的四种情况 int r,c,s1,s2,minn,n; void dfs(int x,int y,int count) { for(int i=0;i<4;i++) //每次位置的四种可能走的四周 都遍历一遍 { int tx=x+dx[i]; //尽量在函数内定义tx,ty 避免全局变量在递归时的影响 int ty=y+dy[i]; if(tx>=0&&ty>=0&&tx<r&&ty<c&&(a[tx][ty]=='.'||a[tx][ty]=='E')) // 前四个判断是否越界,后面判断避免墙(#) { if(a[tx][ty]=='E') //先判断是否已经结束 { if(count<minn) minn=count; n=1; } else { a[tx][ty]='#'; //把走过的地方标记为墙,避免后面的搜索再走 /* for(int i=0;i<r;i++) { printf("\n"); for(int j=0;j<c;j++) printf("%c",a[i][j]); } printf("\n");*/ //输出每步走的地图,这个很实用,观察每一次行走的记录地图,找出欠缺的部分 dfs(tx,ty,count+1); //回溯,把不符合的尝试路径清除,同时把墙(#)变为(.) a[tx][ty]='.'; } } } } int main() { int m,i,j; scanf("%d",&m); while(m--) { memset(a,0,sizeof(a)); minn=100000;n=0; scanf("%d%d",&r,&c); //输入 行 列 for(i=0;i<r;i++) { getchar(); //消除每一行输入后的回车,这个很关键 for(j=0;j<c;j++) { scanf("%c",&a[i][j]); if(a[i][j]=='S') {s1=i;s2=j;} //记录开始的坐标 } } dfs(s1,s2,0); //深搜调用,从S开始,count初始为0 if(!n) printf("impossible\n"); else printf("%d\n",minn+2); // +2是为了把起始S和结束E都算在总步数中 } return 0; }
四、广搜
1、基本思想:运用队列先进先出的特性可以更好的处理下次要走的方向; 广搜可以同时走三个方向,弹出一个方向就再存入弹出的方向能走的三个方向;如此第一次找到符合条件的就是最短路径;2、代码(基本类似于深搜):
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; typedef pair<int ,int> v; //这个是c++ pair运用, typedef自定义了一个pair类型的 v;(内部的两个类型可以任意定义,这里定义为两个整型) queue<v> q; //相当于定义 类型为 pair的队列q int r,c,count,s1,s2,dx[]={-1,0,1,0},dy[]={0,-1,0,1}; char a[100][100]; int b[100][100]; int bfs() { q.push(v(s1,s2)); //存入开始的位置 while(!q.empty()) //判断是否为空,没有满足的可走方向,就不会压入队列元素,就会结束循环 { v p=q.front(); //定义v类型的p 来存储队列q的第一个元素,然后弹出,循环遍历判断存入,弹出位置可走的四个方向 q.pop(); for(int i=0;i<4;i++) { int tx=p.first+dx[i]; int ty=p.second+dy[i]; if(tx>=0&&ty>=0&&tx<r&&ty<c&&a[tx][ty]!='#'&&!b[tx][ty]) { b[tx][ty]=b[p.first][p.second]+1; // a[tx][ty]='#'; 标记没有作用 q.push(v(tx,ty)); if(a[tx][ty]=='E') return b[tx][ty]; //此处的判断应在b[tx][ty]的赋值之后,不然会导致输出结果为0的错误 } } } } int main() { int m,i,j; scanf("%d",&m); while(m--) { memset(a,0,sizeof(a)); count=0; memset(b,0,sizeof(b)); while(!q.empty()) q.pop(); // 清空队列,在多次循环中有着很大作用 scanf("%d%d",&r,&c); //输入 行 列 for(i=0;i<r;i++) { getchar(); for(j=0;j<c;j++) { scanf("%c",&a[i][j]); if(a[i][j]=='S') {s1=i;s2=j;} } } b[s1][s2]=1; printf("%d\n",bfs()); } return 0; }
五、总结
在最短路径方面,广搜有着很大的优势,可以节省很多时间,毕竟不用像深搜一样遍历所有结果才能得到最短的;而且在一些迷宫搜索题目中给出的测试数据一般深搜是很难通过的;推荐使用广搜来寻找最短路径; 这才是搜索的入门阶段,希望可以继续探索更加有趣的难题,有自己的目标才是努力下去的动力,继续努力!相关文章推荐
- 迷宫最短路径
- 迷宫问题的最短路径
- 迷宫问题(求最短路径长度和最短路径)
- 搜索最短路径:迷宫问题 POJ - 3984
- 迷宫的最短路径-BFS算法
- 迷宫的最短路径
- 【深度优先_栈】:输出迷宫的所有路径,并求出最短路径长度及最短路径
- 迷宫最短路径深度优先
- 也谈迷宫算法(最短路径 队列)+源程序
- 迷宫的最短路径(bfs)
- 迷宫最短路径的C++实现(队列:广度优先)
- 迷宫问题,最短路径
- Unity3D之迷宫寻路_A*最短路径寻路
- 迷宫最短路径(bfs)
- 迷宫求解最短路径问题java版
- 【搜索-广搜】 迷宫的最短路径
- 走迷宫 路径最短
- 算12/24点算法 布线问题/迷宫最短路径
- 队列实现求迷宫最短路径(包含每一步的尝试状态,迷宫随机生成)
- 迷宫问题并求最短路径