📘题目描述:
大湾区某城市地铁线路非常密集,乘客很难一眼看出选择哪条线路乘坐更合适。为了解决这个问题,地铁公司希望你开发一个程序,帮助乘客挑选乘坐时间最短的地铁线路。地铁公司提供的数据是:各相邻站点之间的乘坐时间。
🧾 输入格式:
-
第一行是一个整数
N
,表示站点总数(3 ≤ N ≤ 20); -
第二行是两个站点名(单个小写字母),表示出发站和终点站;
-
接下来若干行,每行是:
站点1 站点2 时间
,表示两个相邻站点之间的乘坐时间; -
最后一行为
0000
表示输入结束; -
输入保证一定有唯一解。
🎯 输出格式:
输出乘坐时间最短的线路路径以及总耗时。
🧠 解题思路:
本题可以抽象为图论中的单源最短路径问题,站点是图的节点,相邻站之间的乘坐时间是边的权重。我们可以使用经典的 Dijkstra 算法 来求解最短路径。
关键要点如下:
-
地铁图建模成无向图;
-
使用 优先队列(小顶堆) 加速查找当前最短路径;
-
用
Map<String, String>
记录路径回溯信息; -
最后从终点往回构建最短路径并输出。
✅ Java 代码(含详细注释):
import java.util.*;
public class SubwayShortestPath {
// 边的定义:目标站点 + 花费时间
static class Edge {
String to;
int time;
public Edge(String to, int time) {
this.to = to;
this.time = time;
}
}
// 用于优先队列中记录当前站点和累积时间(用于排序)
static class Node implements Comparable<Node> {
String name;
int cost;
public Node(String name, int cost) {
this.name = name;
this.cost = cost;
}
@Override
public int compareTo(Node other) {
return Integer.compare(this.cost, other.cost); // 最短优先
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 1️⃣ 读取站点总数
int n = Integer.parseInt(sc.nextLine().trim());
// 2️⃣ 读取起点和终点
String[] line = sc.nextLine().trim().split(" ");
String start = line[0];
String end = line[1];
// 3️⃣ 构建图:邻接表
Map<String, List<Edge>> graph = new HashMap<>();
while (sc.hasNext()) {
String str = sc.nextLine().trim();
if (str.equals("0000")) break;
String[] parts = str.split(" ");
String from = parts[0];
String to = parts[1];
int time = Integer.parseInt(parts[2]);
// 无向图(双向添加边)
graph.putIfAbsent(from, new ArrayList<>());
graph.putIfAbsent(to, new ArrayList<>());
graph.get(from).add(new Edge(to, time));
graph.get(to).add(new Edge(from, time));
}
// 4️⃣ Dijkstra 算法核心部分
Map<String, Integer> dist = new HashMap<>(); // 记录最短距离
Map<String, String> prev = new HashMap<>(); // 记录路径回溯
PriorityQueue<Node> pq = new PriorityQueue<>(); // 小顶堆,自动找最短距离的节点
// 初始化距离表
for (String station : graph.keySet()) {
dist.put(station, Integer.MAX_VALUE);
}
dist.put(start, 0); // 起点到自己的距离是0
pq.offer(new Node(start, 0));
while (!pq.isEmpty()) {
Node current = pq.poll();
String u = current.name;
// 如果已经到达终点,可以提前结束
if (u.equals(end)) break;
// 遍历相邻节点
for (Edge e : graph.get(u)) {
int newDist = dist.get(u) + e.time;
if (newDist < dist.get(e.to)) {
dist.put(e.to, newDist);
prev.put(e.to, u); // 记录前驱站点
pq.offer(new Node(e.to, newDist));
}
}
}
// 5️⃣ 回溯路径
List<String> path = new LinkedList<>();
String curr = end;
while (curr != null) {
path.add(0, curr);
curr = prev.get(curr); // 从终点往前找
}
// 6️⃣ 输出结果
System.out.println("最短路径: " + String.join(" -> ", path));
System.out.println("总耗时: " + dist.get(end) + " 分钟");
}
}
🔍 示例测试
输入:
5
a e
a b 3
a c 1
b d 2
c d 4
d e 2
0000
输出:
最短路径: a -> b -> d -> e
总耗时: 7 分钟
📌 小结
-
适合站点较少的小图(3~20个)
-
用
Dijkstra
算法确保最优路径 -
数据结构用得非常清晰:邻接表、优先队列、路径回溯图
-
可扩展性强:如加上站点换乘、票价、时段等