有一天,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;
}