LC 2699. 修改图中的边权
https://leetcode.cn/problems/modify-graph-edge-weights/
完全没有啥思路,看了题目的几个提示之后想到了一个解法,也是这个 题解 里面提到的错误解法。
大致思路就是要做两边最短路:
第一次找destionation -> x的最短路,这里面记录为D1
第二次找source -> x的最短路,并且期间需要使用D1的结果
- 假设当前找到了x, 长度是d, 并且有个(x,y)是不固定边
- 我们现在可以尝试去修改这个(x,y), 让它成为最短路
- 因为D1[y] = dest -> y的最短路径,所以我们可以把(x,y)改为 target - d - D1[y]
但是上面的修改并不一定保证,最后的最短路是 src -> x -> y -> dest. 因为在第一次最短路里面dest->src并不一定经过(x,y)这个节点。
我觉得可能这题最关键就是这里,题解里面提到的:
如果 y 不在最短路上,修改 x - y 并不会对最短路产生影响,所以代码中并没有判断 y 是否在最短路上。
我们每次发现这些边的时候直接去修改就好了,不用判断是否在最短路上。我们假设在最短路上,修改完成之后做一次检查,判断是否满足target就好。
这种两次最短路的算法直接没有看过,比较新鲜。我的代码里面不好直接测试样例,所以增加了一个 `DOCHECK` 标记。
class Solution: def modifiedGraphEdges(self, n: int, edges: List[List[int]], source: int, destination: int, target: int) -> List[ List[int]]: # build adj on fixed cost # assign varied cost with 1. adj = [[] for _ in range(n)] disconnect = set() for a, b, w in edges: if w == -1: disconnect.add((a, b)) disconnect.add((b, a)) w = 1 adj[a].append((b, w)) adj[b].append((a, w)) def shortest(s, e, adj): visit = [-1] * n import heapq hp = [] hp.append((0, s, -1)) while hp: (d, x, p) = heapq.heappop(hp) if visit[x] != -1: continue visit[x] = d if x == e: break for y, w in adj[x]: if visit[y] != -1: continue heapq.heappush(hp, (d + w, y, x)) return visit if True: D1 = shortest(destination, source, adj) d = D1[source] if d > target: return [] # dijkstra again with deterministic order. def fixedWeight(s, e, adj, D): visit = [-1] * n hp = [] hp.append((0, s, -1, 0)) weight = {} while hp: (d, x, p, w) = heapq.heappop(hp) if visit[x] != -1: continue visit[x] = d if p != -1: weight[(x, p)] = w if x == e: break for y, w in adj[x]: if (x, y) in disconnect: if D[y] != -1 and (d + D[y] + w) <= target: w = target - d - D[y] else: w = target + 1 if visit[y] != -1: continue heapq.heappush(hp, (d + w, y, x, w)) return visit, weight D2, W = fixedWeight(source, destination, adj, D1) if D2[destination] != target: return [] output = [] for a, b, w in edges: if w != -1: output.append((a, b, w)) continue w = W.get((a, b)) or W.get((b, a)) or w if w == -1: w = target + 1 output.append((a, b, w)) output = [list(x) for x in output] DOCHECK = False if os.environ.get('USER') == 'dirlt': # print('mother') DOCHECK = True if DOCHECK: def check(edges): adj = [[] for _ in range(n)] for a, b, w in edges: adj[a].append((b, w)) adj[b].append((a, w)) D = shortest(source, destination, adj) if D[destination] != target: print('FAILED', D[destination], target) check(output) return output