Cousera 《Algorithms II》课程作业
Shortest Path (SP) 给定一个加权图,即图的边有权重。求两个节点之间的最短路径(SP)。
SP Assignment
1、三个问题
Q1. Monotonic shortest path - 单调最短路径
给定一个有 E 条边的边加权有向图 G,已知起点 s,找到从 s 到其他每个顶点的 单调最短路径。 一条路径上每个边缘的权重严格增加或严格减少,则该路径是单调的。要求时间复杂度是 O(ElogE)。
题干对于图的限制没有明确说明。但是从复杂度约束 O(ElogE) 来看,可以判断以 Dijkstra 算法为基础。因此我们这里就假设是无负边的图。
那么直接 Dijkstra 更新最小距离的部分加一个判断-当前边和上一条边的权重比较是否单调即可。这里用到了 algs4 中的 DirectedEdge、EdgeWeightedDigraph、IndexMinPQ
A: 在 relax() 时,更新 distTo[] 同时比较单调性。先递增查询一次,再递减查询一次。关键 code 如下: int 变量 ascend 用 1 或 -1 表示单调方向。完整代码 👉 code
1 | private void relax(EdgeWeightedDigraph G, int v, int ascend) { |
参考资料:
Q2. Second shortest path - 次短路径
给定一个加权有向图,令 P 为从顶点 s 到顶点 t 的最短路径。 设计一个 Elog(V) 的算法,以查找从 s 到 t 的除 P 以外最短的路径(不局限于简单路径)。这里假设所有边缘权重严格为正。
无负边使问题简单很多。由于给出了最短路径 P,求第二短的路径,在图中将 P 中最后一条指向 t 的边去掉后,再使用 Dijkstra 算法求解最短路径即可。对于两点之间的路径,当优先队列中加入节点 t 时即可停止。同样这里用到了 algs4 中的 DijkstraSP 等类。
A: 关键 code 如下。使用一个变量 delEdge 保存最短路径中到达节点 t 的边。去掉该边,再次寻找 s-t 的最短路径。若客户端没有给出最短路径,可以先运行一遍 Dijkstra 找出。最关键是找到需要去掉的边。完整代码 👉 code
1 | public class SecondSP { |
Q3. Shortest path with one skippable edge - 拥有一条可跳过的边的最短路径
给定一个加权有向图,设计一个 O(ElogV) 算法以找到从 s 到 t 的最短路径,可以将其中任何一条边的权重改为 0。假设边的权重都是非负的。
不是很理解这题意思。这题直接看的 solution:计算从 s 到其他每个顶点的最短路径,再计算从每个顶点到 t 的最短路径。 对于每个边 e=(v, w),计算从 s 到 v 的最短路径的长度与从 w 到 t 的最短路径的长度之和。总和最小的路径即为解。按照 solution 的意思:将图中任意一条边权重改为 0,那会产生 e 个新的图,求这 e 个图里 s-t 的最短路径。那么还是要用到 algs4 中的 DijkstraSP 类。之后简单遍历寻找即可。
A: 代码如下,用一个 DijkstraSP 数组保存每个节点的最短路径树。再按照 Solution 判断即可。需要用一个 Iterable 的变量保存最后的路径。
1 | public class EdgeSkippableSP { |