走出迷宫、迷宫问题(思路讲解、模板)【深度优先搜索】

走出迷宫

题目链接(点击)

当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单。

假设你已经得到了一个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;
}

 

posted @ 2019-03-16 20:51  XJHui  阅读(1290)  评论(0编辑  收藏  举报