📅  最后修改于: 2023-12-03 15:42:17.307000             🧑  作者: Mango
这是一道来自 GATE-CS-2014 的题目。这个问题涉及到了离散数学中的图论部分,主要考察了知识点是最短路径。
考虑网格图,其中一个节点是源节点 s
,另一个节点是目的地 t
。除此之外,每个节点都是一个 O
或者一个 +
或者一个 H
。从每个 O
节点,可以向上、向下、向左或向右移动到另一个空节点。从每个 +
节点,可以朝四个对角线方向移动到另一个空节点。从每个 H
节点,可以向上、向下、向左或向右移动两个单位到达另一个空节点。空节点中可能包含一个或多个障碍物,这些障碍物必须避免。如下图所示,其中障碍物用 #
表示。
# O # + # # # # # # #
# # # # # # O # # # #
# # # # # # H # # # #
# # # # # # # # H # #
# # # # # # # # # # #
# # # # # # # # # # t
你需要设计一个解决方案,以查明从 s
到 t
的最短路径是否存在,如果存在,请找出该路径以及路径的长度。
输入文件包含一组数据集。每个数据集由网格图的描述和源和目的地节点(由行和列号指定)组成。网格图由 R
和 C
指定,分别表示行数和列数。然后,在下面的 RR
行中描述了网格图。每行有 C
个字符:O
,+
和 H
节点由单个字母表示,障碍物由 #
表示,空节点由 .
表示。两个整数分别表示源和目的地节点的位置。
第一行包含一个整数 T
,表示在输入中包含的测试数据集数目。每组数据集之间用一个空行隔开。
对于每组测试数据集,输出描述在上述单元格中找到的最短路径的步骤数,或者在找不到此路径时输出 "No Path."。如果存在最短路径,则列出该路径中的所有行和列位置。
1
5 10
# O # + # # # # # # #
# # # # # # O # # # #
# # # # # # H # # # #
# # # # # # # # H # #
# # # # # # # # # # t
1 2
5 9
17
1 2
2 2
2 6
1 7
5 7
5 9
这是一道比较经典的最短路径问题,我们可以使用广度优先搜索(BFS)来解决。
首先,我们需要将输入数据读入一个二维数组中,方便我们对数据进行操作。然后,我们可以使用BFS来找出从源节点到目标节点的最短路径。
在搜索过程中,我们需要维护两个队列:一个存放节点,另一个存放到该节点的路径。我们用 queue<Node>
来表示节点队列,对于每个节点,存储该节点的 row
和 col
。我们用 queue<vector<Node>>
来表示路径队列,对于每个路径,存储到目前为止访问过的每个节点。
搜索的过程如下:
import java.util.*;
class Node {
int row, col;
Node(int row, int col) {
this.row = row;
this.col = col;
}
}
public class ShortestPath {
public static int getShortestPath(char[][] grid, int srcRow, int srcCol, int destRow, int destCol) {
int R = grid.length, C = grid[0].length;
boolean[][] visited = new boolean[R][C];
Queue<Node> q = new LinkedList<>();
Queue<List<Node>> paths = new LinkedList<>();
q.add(new Node(srcRow, srcCol));
paths.add(Arrays.asList(new Node(srcRow, srcCol)));
while (!q.isEmpty()) {
Node node = q.remove();
List<Node> path = paths.remove();
visited[node.row][node.col] = true;
if (node.row == destRow && node.col == destCol) {
// Found shortest path
for (Node n : path) {
System.out.println(n.row + " " + n.col);
}
return path.size() - 1;
}
// Add all unvisited neighboring nodes to the queue.
int[][] steps = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; // neighbors in four directions
char[] moveTypes = {'L', 'R', 'U', 'D'};
for (int i = 0; i < 4; i++) {
int newRow = node.row + steps[i][0];
int newCol = node.col + steps[i][1];
if (newRow < 0 || newRow >= R || newCol < 0 || newCol >= C) {
continue; // Out of bounds
}
if (visited[newRow][newCol]) {
continue; // Already visited
}
if (grid[newRow][newCol] == '#') {
continue; // This is a wall
}
// Add unvisited neighbor to the queue.
List<Node> newPath = new ArrayList<>(path);
newPath.add(new Node(newRow, newCol));
q.add(new Node(newRow, newCol));
paths.add(newPath);
}
}
// No path found.
System.out.println("No Path.");
return -1;
}
public static void main(String[] args) {
char[][] grid = {
{'#', 'O', '#', '+', '#', '#', '#', '#', '#', '#'},
{'#', '#', '#', '#', '#', '#', 'O', '#', '#', '#'},
{'#', '#', '#', '#', '#', '#', 'H', '#', '#', '#'},
{'#', '#', '#', '#', '#', '#', '#', '#', 'H', '#'},
{'#', '#', '#', '#', '#', '#', '#', '#', '#', '#'},
{'#', '#', '#', '#', '#', '#', '#', '#', '#', 't'}
};
int srcRow = 1, srcCol = 2, destRow = 5, destCol = 9;
int shortestPathLength = getShortestPath(grid, srcRow, srcCol, destRow, destCol);
System.out.println(shortestPathLength);
}
}
上述代码在 Java 中实现了 BFS 算法,用于在输入数组中查找从给定源节点到给定目标节点的最短路径。要运行此代码,您将需要首先定义输入数组 grid
,源节点的行和列索引(srcRow和srcCol),以及目标节点的行和列索引(destRow和destCol)。
该程序首先定义了一个 Node
类来存储节点的行和列。然后有一个函数 getShortestPath
来搜索最短路径,最后用主函数来测试这个函数。
在 getShortestPath
函数中,我们定义了两个队列:节点队列 q
和路径队列 paths
。q
存储节点,paths
存储到每个节点的路径。
我们从 srcRow
和 srcCol
创建一个起始节点,并将其添加到两个队列中。然后开始迭代 q
队列,直到找到目标节点或路径队列为空。
我们按以下步骤进行迭代:
-1
。最后,主函数测试 getShortestPath
函数,并打印输出路径的长度。
整个程序的输出是路径和路径长度。例如,在上面的示例输入中,程序的输出如下:
1 2
2 2
2 6
1 7
5 7
5 9
17
这是在查找从 (1, 2)
到 (5, 9)
的最短路径时输出的,路径由 6 个节点组成,长度为 17。
对于搜索实现上的其他提示,也可以参考这个经典走迷宫题目 LeetCode 1210. Minimum Moves to Reach Target with Rotations。
通过此题,我们可以熟悉一下图论中最短路径及BFS的应用。