前言
看了华为2025年四月份的机考题目,有好多道涉及图论,其中Dijkstra算法考核较为频繁,因此通过此篇记录一下。
关于Dijkstra算法的分析逻辑:https://programmercarl.com/kamacoder/0047.参会dijkstra朴素.html#思路
在本站的笔记中有记录到Dijkstra算法的实现:【卡码网-47】参加科学大会
但是今天亲手试了一下华为的机考真题,发现有很多问题,其中最主要的就是节点的值为String
类型,我在网上搜了大量的博文,发现它们的示例题目中节点的值均为int
类型,这就意味着它们可以通过构造简单的int[][]
二维矩阵去维护邻接表,而如果节点的值为String
类型显然不可用此方法。
题目
题目描述(2025.04.09华为机考第二题)
大湾区某城市地铁线路非常密集,乘客很难一眼看出选择哪条线路乘型比较合适,为了解决这个问题,地铁公司希望你开发一个程序帮助乘客挑选合适的乘坐线路,使得乘坐时间最短,地铁公司可以提供的数据是各相邻站点之间的乘坐时间。
输入描述
第一行:N,站点总数,3 <= N <= 20.
第二行:乘客的出发和到达站点。
第三行起:相邻站点之间的乘坐时间,每对站点一行,站点名称是单个小写字母,站点名一定包括出发和到达站点,输入保证只有一个唯一解。
结束行:0000
输出描述(有修改)
最小花费
耗时最短的线路
样例1
输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 12 a e a b 2 b c 2 c d 2 d e 2 f b 3 b g 3 g h 2 h i 3 i h 2 h e 3 e k 2 k l 4 0000
|
输出
样例2
输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 12 f k a b 2 b c 2 c d 2 d e 2 f b 3 b g 3 g h 2 h i 3 j h 2 h e 3 e k 2 k l 4 0000
|
输出
题解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| import java.util.*;
public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
String start = sc.next(); String end = sc.next();
Map<String, Map<String, Integer>> graph = new HashMap<>();
Set<String> nodes = new HashSet<>();
while (true) { String p1 = sc.next(); if(p1.equals("0000")) { break; } String p2 = sc.next(); int val = sc.nextInt(); nodes.add(p1); nodes.add(p2);
graph.putIfAbsent(p1, new HashMap<>()); graph.get(p1).put(p2, val); }
Map<String, Integer> minDist = new HashMap<>(); for (String node : nodes) { minDist.put(node, Integer.MAX_VALUE); } minDist.put(start, 0);
Map<String, Boolean> visited = new HashMap<>(); for (String node : nodes) { visited.put(node, false); }
Map<String, String> parent = new HashMap<>();
int COUNT = N; while (COUNT > 0) { int minVal = Integer.MAX_VALUE; String curNode = start;
for (String node : nodes) { if (!visited.get(node) && minDist.get(node) < minVal) { minVal = minDist.get(node); curNode = node; } }
visited.put(curNode, true);
if (graph.containsKey(curNode)) { for (Map.Entry<String, Integer> entry : graph.get(curNode).entrySet()) { String nextNode = entry.getKey(); int val = entry.getValue(); if (!visited.get(nextNode) && minDist.get(curNode) + val < minDist.get(nextNode)) { minDist.put(nextNode, minDist.get(curNode) + val); parent.put(nextNode, curNode); } } } COUNT--; }
if (minDist.get(end) == Integer.MAX_VALUE) { System.out.println(-1); return; } else { System.out.println(minDist.get(end)); }
List<String> path = new ArrayList<>(); String cur = end; while (cur != null && !cur.equals(start)) { path.add(0, cur); cur = parent.get(cur); } path.add(0, start);
for (int i = 0; i < path.size(); i++) { if (i != path.size() - 1) { System.out.print(path.get(i) + "->"); } else { System.out.print(path.get(i)); } } } }
|
说明:
-
如果遇到节点值为String
类型,可以利用Map集合构造邻接表。泛型说明:<起点, <终点, 相邻节点间的权重>>
-
因为使用不了矩阵,因此需要利用Set
集合存储节点,用于后续的遍历操作。
-
Map
中的putIfAbsent()
方法说明:如果指定的键已经存在,则该方法不会执行任何操作(避免将原有的内容覆盖掉),相当于以下代码:
1 2 3 4 5
| if(graph.containsKey(p1)) { } else { graph.put(p1, new HashMap<>()); }
|
后记
题目来源:https://mp.weixin.qq.com/s/TrBWkqv3GbjDvttrU3Mx4A
额外说明:如果节点数目很少(如本题),可以采用DFS暴力搜索解决。