走出迷宫、迷宫问题(思路讲解、模板)【深度优先搜索】
走出迷宫
当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单。
假设你已经得到了一个n*m的迷宫的图纸,请你找出从起点到出口的最短路。
输入
第一行是两个整数n和m(1≤n,m≤100),表示迷宫的行数和列数。
接下来n行,每行一个长为m的字符串,表示整个迷宫的布局。字符‘.’表示空地,‘#’表示墙,‘S’表示起点,‘T’表示出口。
输出
输出从起点到出口最少需要走的步数。
样例输入
3 3
S#T
.#.
...
样例输出
6
思路:
之前学长讲过bfs和dfs的知识,但是因为当时没做太多例题也没有太好的掌握这些知识,昨天看到迷宫这道题目就又看了看,但是不知道怎么下手,就又学了一下
在矩阵中输入不同的字符要求从S出发到T 只能走 ‘ . ’ 问最少的步数
深度优先搜索在这个题中相当于暴力每种可以走的路径 找到最短的一条路(通过递归实现)
其好处就是:在走每种路径时可以记录所走的总步数 并且在终点处可以更新最少的步数然后输出
AC代码:
#include<stdio.h>
const int MAX=1e5;
int n,m,sum=MAX;
int be1,be2,en1,en2;
int dir[4][2]={0,1,0,-1,1,0,-1,0};
char a[105][105];
void dfs(int x,int y,int sum1)
{
if(x==en1&&y==en2){ //递归的最后终点 开始 return
if(sum>sum1){ //加if 更新最小步数
sum=sum1;
}
return;
}
for(int i=0;i<4;i++){
x+=dir[i][0]; //借助方向数组dir改变x和y的值 实现走下一步
y+=dir[i][1];
if((a[x][y]=='.'||a[x][y]=='T')&&x>=0&&x<n&&y>=0&&y<m){
a[x][y]='#'; //x和y必须严格控制在矩阵内部
dfs(x,y,sum1+1);
a[x][y]='.';
}
x-=dir[i][0]; //实现返回
y-=dir[i][1];
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%s",a[i]);
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(a[i][j]=='S'){ // 要知道开始点和结束点的位置才能bfs
be1=i;
be2=j;
}
else if(a[i][j]=='T'){
en1=i;
en2=j;
}
}
}
bfs(be1,be2,0); //sum1位置是从0开始
printf("%d\n",sum);
return 0;
}
迷宫问题
定义一个二维数组:
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表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
Output
左上角到右下角的最短路径,格式如样例所示。
Sample Input
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
Sample Output
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
思路:
做了上面那个题又找了道新题试了试
输出从左上角到右下角最短的路径
区别是这道题不需要遍历找到开始和结束的点 但要输出路径 在递归暴力的时候可以看得出来 最终的路径并不是连续的 也就是说将每次递归x和y的值存起来然后输出是不太容易实现的 例如下面这个例子就特别麻烦
想了好久 最后还是把x和y和sum1(到达每个点的最小步数)分别
输出找到了方法:
最终目标是4 4 点 从4 4 点开始往上找
4 4 对应的sum1是7 则 下一步应该找6 让后是5…… 输出对应x和y就可以了
AC代码:
#include<stdio.h>
const int MAX=1e6;
int sum=MAX;
int a[15][15];
int dir[4][2]={0,1,0,-1,1,0,-1,0,};
struct node{
int num;
int x;
int y;
}edge[MAX+5];
struct node1{
int x;
int y;
}edge1[MAX+5];
int count=0;
void dfs(int x,int y,int sum1)
{
if(x==4&&y==4){
if(sum>sum1){
sum=sum1;
}
return;
}
for(int i=0;i<4;i++){
x+=dir[i][0];
y+=dir[i][1];
if(a[x][y]==0&&x>=0&&x<=4&&y>=0&&y<=4){
a[x][y]=1;
edge[count].num=sum1;
edge[count].x=x;
edge[count++].y=y;
dfs(x,y,sum1+1);
a[x][y]=0;
}
x-=dir[i][0];
y-=dir[i][1];
}
}
int main()
{
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
scanf("%d",&a[i][j]);
}
}
dfs(0,0,0); //下面的代码虽然看起来复杂但目的就是从后往前找sum1更小的值
printf("(0, 0)\n");
int count1=0;
for(int i=count-1;i>=0;i--){
if(edge[i].x==4&&edge[i].y==4){
int count2;
for(int j=i;j>=0;j--){
if(edge[j].num<count2){
edge1[count1].x=edge[j].x;
edge1[count1++].y=edge[j].y;
count2=edge[j].num;
}
}
for(int j=count1-1;j>=0;j--){
printf("(%d, %d)\n",edge1[j].x,edge1[j].y);
}
return 0;
}
}
return 0;
}