证明:由于除去起点的其余 dis}[i] 都不低于 dis}[x],且图中边权都非负,那么从另外一个点 y 去更新 dis}[x] 时,是无法让 dis}[x] 变得更小的(因为 dis}[x] 是当前最小),因此 dis}[x] 已经是从 start 到 x 的最短路的长度了。
由于在寻找 dis 的最小值时,需要排除在前面的循环中找到的 x(因为已经更新 x 到其它点的最短路了,无需反复更新),可以用一个 vis 数组标记这些 x。
以上,通过数学归纳法,可以证明每次找到的未被标记的 dis 的最小值就是最短路。
由于图是稠密图,所以用朴素 Dijkstra 求最短路。
[sol1-Python3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution: defminimumCost(self, start: List[int], target: List[int], specialRoads: List[List[int]]) -> int: t = tuple(target) dis = defaultdict(lambda: inf) dis[tuple(start)] = 0 vis = set() whileTrue: v, dv = None, -1 for p, d in dis.items(): if p notin vis and (dv < 0or d < dv): v, dv = p, d if v == t: return dv # 到终点的最短路已确定 vis.add(v) vx, vy = v dis[t] = min(dis[t], dv + t[0] - vx + t[1] - vy) # 更新到终点的最短路 for x1, y1, x2, y2, cost in specialRoads: w = (x2, y2) dis[w] = min(dis[w], dv + abs(x1 - vx) + abs(y1 - vy) + cost)
funcminimumCost(start, target []int, specialRoads [][]int)int { type pair struct{ x, y int } t := pair{target[0], target[1]} dis := make(map[pair]int, len(specialRoads)+2) dis[t] = math.MaxInt dis[pair{start[0], start[1]}] = 0 vis := make(map[pair]bool, len(specialRoads)+1) // 终点不用记 for { v, dv := pair{}, -1 for p, d := range dis { if !vis[p] && (dv < 0 || d < dv) { v, dv = p, d } } if v == t { // 到终点的最短路已确定 return dv } vis[v] = true dis[t] = min(dis[t], dv+t.x-v.x+t.y-v.y) // 更新到终点的最短路 for _, r := range specialRoads { w := pair{r[2], r[3]} d := dv + abs(r[0]-v.x) + abs(r[1]-v.y) + r[4] if dw, ok := dis[w]; !ok || d < dw { dis[w] = d } } } }
funcabs(x int)int { if x < 0 { return -x }; return x } funcmin(a, b int)int { if b < a { return b }; return a }