DFS应用

有一天,A一个人去玩迷宫。但是方向感不好的它迷路了。B得知后便要去解救A,B显然是有备而来,已经是知道了迷宫的地图,但是B现在要以最快的速度去解决A。那么问题就从现在开始了。

​ 迷宫由n行m列的单元格组成,每个单元格要么是空地,要么就是障碍物。你的任务是帮助B选择一个从迷宫起点到A所在位置的最短路径。注意:障碍物是不能走的,当然B也不能走到迷宫之外。

​ 首先,我们当然需要一个二维数组来存储这个迷宫,刚开始的时候,B处于迷宫的入口处(0, 0)。A处于(p,q)。其实,就是从(1,1)

到(p,q)的最短路径,如果你是B的话你要怎么走呢。如果有两个B就好了,那么就能测试开始的时候是往右走还是往下走。但是现在只有一个B,所以只能一个一个去尝试。那么我们先让B往右走,直到走不通的时候再回到这,再去尝试另一个方向。我们这里规定一个顺序,按照顺时针方向来尝试。

​ 我们看到了B第一步只能走(0,1)和(1, 0)。那么按照刚才的策略,我们先让B往右走,现在B就来到了(0,1)这个点,然后来到了这里以后呢,然后又能去到哪些点?只有(1,1)这个点,因为(0, 2)这个点事带有障碍物的,无法抵达这个点,后续又会继续走新的点,之后的障碍物点不能走,已经走过的点也不能走,一直走到找到A为止。但是这里要注意了,并不是找到了A就结束了,我们要找到是最短的路径,这里的尝试可能并不是最短的路径。刚才在选择方向的地方有很多种选择,因此我们需要返回这些地方尝试别的走别的方向,直到把所有的方向都走一遍,最后输出一条最短的路径。

​ 现在我们就尝试一下DFS来实现这个方法。首先看DFS函数要如何来写。DFS函数的功能是解决当前位置需要干什么。而B处在某个点的时候需要处理的是:先检查B是否已经到达了A的位置,如果没有那么则要找出下一步要怎么走。为了解决这个问题,此处DFS函数应该至少要输入3个参数,分别是当前的X坐标,Y坐标,已经走过的步数。

void DFS(int x, int y, int step)
{
    return;
}

​ 判断是否到达A的位置这个很好实现,只需要判断当前的坐标是否和A的坐标是相等就可以了,如果相等就表示B已经到达了A的位置

void DFS(int x, int y, int step)
{
    // 判断是否到达A的位置
    if (x == p && y == q) {
        // 更新最小值
        if (step < min) {
            min = step;
        }
        return; // 如果已经找到A,即可返回
    }
    return;
}

​ 如果没有找到A的话,则需要找出下一步可以走的地方。因为有四个方向可以走,根据我们之前的策略,按照之前的顺时针方向来尝试,这里为了编程方便定义一个数组next:

int next[4][2] = {{0, 1},   // 右
                  {1, 0},   // 下
                  {0, -1},  // 左
                  {-1, 0}}; // 上

​ 通过这个数组,我们使用循环就很容易获取下一步的坐标。这里将下一步的横坐标用tx来存储,纵坐标用ty来存储:

for (k = 0; k <= 3; k++) {
    // 计算下一个点的坐标
    tx = x + next[k][0];
    ty = x + next[k][1];
}

​ 接下来我们就要对下一步的坐标进行一些校验和判断:是否越界,是否为障碍物,是否已经在路径中。需要用一个book[tx] [ty]来记录每一个是否在路径中。

​ 如果这个点符合所有的要求,就对这个点进行下一步的拓展,即DFS(tx, ty, step + 1),注意这个是step+1,因为你一旦往下继续尝试了的话,那么就意味着你的部署增加了1。

for (k = 0; k <= 3; k++) {
    // 计算下一个点的坐标
    tx = x + next[k][0];
    ty = x + next[k][1];
    
    // 判断是否已经越界
    if (tx < 0 || tx >= n || ty < 0 || ty >= m) {
        continue;
    }
    
    // 判断是否为障碍物或者已经在路径中
    if (a[tx][ty] == 0 && book[tx][ty] == 0) {
        book[tx][ty] == 1; // 标记这个点是否已经走过
        DFS(tx, ty, step + 1); // 开始尝试下一个点
        book[tx][ty] = 0; // 尝试结束取消这个点的标记
    }
}

​ 完整代码如下:

#include <stdio.h>

int n, m, p, q, min = 99999999;
int a[51][51], book[51][51];

void DFS(int x, int y, int step)
{
    int next[4][2] = {{0, 1},   // 右
                  	  {1, 0},   // 下
                  	  {0, -1},  // 左
                  	  {-1, 0}}; // 上
    
    int tx, ty, k;
    // 判断是否B是否到达A的位置
    if (x == p && y == q) {
        // 更新最小值
        if (step < min) {
            min = step;
        }
        return;
    }
    
    // 枚举4种走法
    for (k = 0; k <= 3; k++) {
        // 计算下一个点的坐标
    	tx = x + next[k][0];
    	ty = y + next[k][1];
    
    	// 判断是否已经越界
    	if (tx < 1 || tx > n || ty < 1 || ty > m) {
        	continue;
    	}
    
    	// 判断是否为障碍物或者已经在路径中
    	if (a[tx][ty] == 0 && book[tx][ty] == 0) {
        	book[tx][ty] = 1; // 标记这个点是否已经走过
        	DFS(tx, ty, step + 1); // 开始尝试下一个点
        	book[tx][ty] = 0; // 尝试结束取消这个点的标记
    	}
    }
    return;
}

int main()
{
    int i, j, startx, starty;
    // 读入n和m,n为行,m为列
    scanf("%d %d", &n, &m);
    
    // 读入迷宫
    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            scanf("%d", &a[i][j]);
        }
    }
    
    // 读入起始点和终点坐标
    scanf("%d %d %d %d", &startx, &starty, &p, &q);
    
    // 从开始进行搜索
    book[startx][starty] = 1;
    // 第一个参数是起点x坐标,第二个参数是起点y坐标,第三个坐标是初始步数是0
    DFS(startx, starty, 0);
    
    // 输出最短步数
    printf("%d", min);
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值