迷宫问题
定义一个二维数组:
int maze[n][m];
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
(0,0)
(1,0)
(2,0)
(2,1)
(2,2)
(2,3)
(2,4)
(3,4)
(4,4)
原题中给的测试用例不适合举例,我决定重新给一个测试用例。
int maze[6][7] = {
0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 0,
0, 1, 0, 0, 0, 1, 0,
0, 1, 0, 1, 0, 0, 0,
0, 1, 0, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0,
};
根据观察,我们可得找到两条路径。显然,走蓝色这条的路径是最短的。
根据以上例子,我们得到了大概的思路:
ArrayList>
)保存每一条能够到达终点的路径在使用 深度优先搜索的过程中,要注意一下几点:
static ArrayList<ArrayList<Integer>> res = new ArrayList<>();
public static void main(String[] args) {
//利用 Scanner 读入数据
Scanner sc = new Scanner(System.in);
//拥有多组数据
while (sc.hasNextInt()) {
//读入列和行
int n = sc.nextInt();
int m = sc.nextInt();
//读入数组
int[][] maze = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
maze[i][j] = sc.nextInt();
}
}
// 第一步
//创建一个 ArrayList step 记录步数
ArrayList<Integer> step = new ArrayList<>();
//调用 dfs 函数
dfs(maze,0,0,n,m,step);
// 第三步
//得到结果 筛选最短路径
int size = Integer.MAX_VALUE;
int index = 0;
for (int i = 0; i < res.size(); i++) {
if (res.get(i).size() < size) {
size = res.get(i).size();
index = i;
}
}
//第三步
//将最短路径保存并输出
step = res.get(index);
for (int i = 0; i < step.size(); i+=2) {
System.out.println("(" + step.get(i) + "," + step.get(i+1) + ")");
}
// 清空 res 继续下一个迷宫
// 这一步其实不仅仅是循环输入的时候用到
//个人觉得清除后可以节省空间。
res.clear();
}
}
public static void dfs(int[][] maze,int i,int j,int n,int m,ArrayList<Integer> step) {
// 越界 、 有墙 、 已经走过
if (i < 0 || i >= n || j < 0 || j >= m || maze[i][j] == 1 || maze[i][j] == 2) {
return;
}
//如果到达终点
if (i == n - 1 && j == m - 1) {
//添加终点坐标
step.add(i);
step.add(j);
res.add(new ArrayList<>(step));
//回溯
step.remove(step.size() - 1);
step.remove(step.size() - 1);
}
//没有到达终点
else {
//添加当前坐标
step.add(i);
step.add(j);
//标记为已经走过
maze[i][j] = 2;
// 递归
dfs(maze, i + 1, j, n, m, step);
dfs(maze, i, j + 1, n, m, step);
dfs(maze, i - 1, j, n, m, step);
dfs(maze, i, j - 1, n, m, step);
// 回溯
maze[i][j] = 0;
step.remove(step.size() - 1);
step.remove(step.size() - 1);
}
}
从 i == 0 到 i == 4,并未出现越界、墙、已经走过的情况,step.add(i,0)
i == 5, j == 0, 下一次递归 i == 5,存在越界,返回到上一步继续递归 dfs(maze, i, j + 1, n, m, step), step.add(5,0);
i == 5, j == 1, 下一次递归调用dfs(maze, i + 1, j, n, m, step), i == 5, 存在越界,返回到上一步 j == 1, 继续递归dfs(maze, i, j + 1, n, m, step),step.add(5,1);
i == 5, j == 2, 下一次递归调用dfs(maze, i + 1, j, n, m, step), i == 5, 存在越界,返回到上一步 j == 2, 继续递归dfs(maze, i, j + 1, n, m, step),step.add(5,2);
i == 5, j == 3, 下一次递归调用dfs(maze, i + 1, j, n, m, step), i == 5, 存在越界,返回到上一步 j == 3, 继续递归dfs(maze, i, j + 1, n, m, step),step.add(5,3);
i == 5, j == 4, 下一次递归调用dfs(maze, i + 1, j, n, m, step), i == 5, 存在越界,返回到上一步 j == 4, 继续递归dfs(maze, i, j + 1, n, m, step),step.add(5,4);
i == 5, j == 5, 下一次递归调用dfs(maze, i + 1, j, n, m, step), i == 5, 存在越界,返回到上一步 j == 5, 继续递归dfs(maze, i, j + 1, n, m, step),step.add(5,5);
i == 5, j == 6, 满足 i == n-1 && j == m-1, step.add(5,6), res.add(new ArrayList<Integer>(step))