📜  门| GATE-CS-2014-(Set-2) |问题 14(1)

📅  最后修改于: 2023-12-03 15:42:17.307000             🧑  作者: Mango

门- GATE-CS-2014-(Set-2) - 问题 14

这是一道来自 GATE-CS-2014 的题目。这个问题涉及到了离散数学中的图论部分,主要考察了知识点是最短路径。

问题描述

考虑网格图,其中一个节点是源节点 s,另一个节点是目的地 t。除此之外,每个节点都是一个 O 或者一个 + 或者一个 H。从每个 O 节点,可以向上、向下、向左或向右移动到另一个空节点。从每个 + 节点,可以朝四个对角线方向移动到另一个空节点。从每个 H 节点,可以向上、向下、向左或向右移动两个单位到达另一个空节点。空节点中可能包含一个或多个障碍物,这些障碍物必须避免。如下图所示,其中障碍物用 # 表示。

# O # + # # # # # # #
# # # # # # O # # # #
# # # # # # H # # # #
# # # # # # # # H # #
# # # # # # # # # # #
# # # # # # # # # # t

你需要设计一个解决方案,以查明从 st 的最短路径是否存在,如果存在,请找出该路径以及路径的长度。

输入

输入文件包含一组数据集。每个数据集由网格图的描述和源和目的地节点(由行和列号指定)组成。网格图由 RC 指定,分别表示行数和列数。然后,在下面的 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> 来表示节点队列,对于每个节点,存储该节点的 rowcol。我们用 queue<vector<Node>> 来表示路径队列,对于每个路径,存储到目前为止访问过的每个节点。

搜索的过程如下:

  1. 将源节点入队。
  2. 只要节点队列不为空,就执行以下操作:
    • 取出节点队列的队首节点,同时取出路径队列的相同位置上的路径。
    • 如果该节点是目标节点,我们就找到了最短路径,输出路径的长度和路径本身。
    • 否则,将该节点的四个方向上能走的节点入队,并且将这些节点添加到路径队列上。
    • 重复步骤 2。
代码实现
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 和路径队列 pathsq 存储节点,paths 存储到每个节点的路径。

我们从 srcRowsrcCol 创建一个起始节点,并将其添加到两个队列中。然后开始迭代 q 队列,直到找到目标节点或路径队列为空。

我们按以下步骤进行迭代:

  1. 删除队列中的下一个节点和相应的路径
  2. 如果找到了目标节点,则说明我们找到了最短路径,输出路径上的每个节点并返回路径长度
  3. 如果不是,则添加该节点的四个相邻节点到队列中,同时添加到相应的路径上。如果相邻节点已经访问过,或者是墙壁,则将其略过。如果页面大小不被重题阻挡,则进行标记是否访问通过。
  4. 如果到现在为止还没有找到路径,则说明不存在路径,输出 "No Path." 并返回 -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的应用。