class Solution {
public:
vector<vector<int>> modifiedGraphEdges(int n, vector<vector<int>>& edges, int source, int destination, int target) {
}
};
6442. 修改图中的边权
给你一个 n
个节点的 无向带权连通 图,节点编号为 0
到 n - 1
,再给你一个整数数组 edges
,其中 edges[i] = [ai, bi, wi]
表示节点 ai
和 bi
之间有一条边权为 wi
的边。
部分边的边权为 -1
(wi = -1
),其他边的边权都为 正 数(wi > 0
)。
你需要将所有边权为 -1
的边都修改为范围 [1, 2 * 109]
中的 正整数 ,使得从节点 source
到节点 destination
的 最短距离 为整数 target
。如果有 多种 修改方案可以使 source
和 destination
之间的最短距离等于 target
,你可以返回任意一种方案。
如果存在使 source
到 destination
最短距离为 target
的方案,请你按任意顺序返回包含所有边的数组(包括未修改边权的边)。如果不存在这样的方案,请你返回一个 空数组 。
注意:你不能修改一开始边权为正数的边。
示例 1:
输入:n = 5, edges = [[4,1,-1],[2,0,-1],[0,3,-1],[4,3,-1]], source = 0, destination = 1, target = 5 输出:[[4,1,1],[2,0,1],[0,3,3],[4,3,1]] 解释:上图展示了一个满足题意的修改方案,从 0 到 1 的最短距离为 5 。
示例 2:
输入:n = 3, edges = [[0,1,-1],[0,2,5]], source = 0, destination = 2, target = 6 输出:[] 解释:上图是一开始的图。没有办法通过修改边权为 -1 的边,使得 0 到 2 的最短距离等于 6 ,所以返回一个空数组。
示例 3:
输入:n = 4, edges = [[1,0,4],[1,2,3],[2,3,5],[0,3,-1]], source = 0, destination = 2, target = 6 输出:[[1,0,4],[1,2,3],[2,3,5],[0,3,1]] 解释:上图展示了一个满足题意的修改方案,从 0 到 2 的最短距离为 6 。
提示:
1 <= n <= 100
1 <= edges.length <= n * (n - 1) / 2
edges[i].length == 3
0 <= ai, bi < n
wi = -1
或者 1 <= wi <= 107
ai != bi
0 <= source, destination < n
source != destination
1 <= target <= 109
原站题解
golang 解法, 执行用时: 304 ms, 内存消耗: 7.5 MB, 提交时间: 2023-05-23 10:07:29
func modifiedGraphEdges(n int, edges [][]int, source, destination, target int) [][]int { type edge struct{ to, eid int } g := make([][]edge, n) for i, e := range edges { x, y := e[0], e[1] g[x] = append(g[x], edge{y, i}) g[y] = append(g[y], edge{x, i}) // 建图,额外记录边的编号 } var delta int dis := make([][2]int, n) for i := range dis { dis[i] = [2]int{math.MaxInt, math.MaxInt} } dis[source] = [2]int{} dijkstra := func(k int) { // 这里 k 表示第一次/第二次 vis := make([]bool, n) for { // 找到当前最短路,去更新它的邻居的最短路 // 根据数学归纳法,dis[x][k] 一定是最短路长度 x := -1 for y, b := range vis { if !b && (x < 0 || dis[y][k] < dis[x][k]) { x = y } } if x == destination { // 起点 source 到终点 destination 的最短路已确定 return } vis[x] = true // 标记,在后续的循环中无需反复更新 x 到其余点的最短路长度 for _, e := range g[x] { y, wt := e.to, edges[e.eid][2] if wt == -1 { wt = 1 // -1 改成 1 } if k == 1 && edges[e.eid][2] == -1 { // 第二次 Dijkstra,改成 w w := delta + dis[y][0] - dis[x][1] if w > wt { wt = w edges[e.eid][2] = w // 直接在 edges 上修改 } } // 更新最短路 dis[y][k] = min(dis[y][k], dis[x][k]+wt) } } } dijkstra(0) delta = target - dis[destination][0] if delta < 0 { // -1 全改为 1 时,最短路比 target 还大 return nil } dijkstra(1) if dis[destination][1] < target { // 最短路无法再变大,无法达到 target return nil } for _, e := range edges { if e[2] == -1 { // 剩余没修改的边全部改成 1 e[2] = 1 } } return edges } func min(a, b int) int { if b < a { return b }; return a }
java 解法, 执行用时: 18 ms, 内存消耗: 47.8 MB, 提交时间: 2023-05-23 10:07:03
class Solution { public int[][] modifiedGraphEdges(int n, int[][] edges, int source, int destination, int target) { List<int[]> g[] = new ArrayList[n]; Arrays.setAll(g, e -> new ArrayList<>()); for (int i = 0; i < edges.length; i++) { int x = edges[i][0], y = edges[i][1]; g[x].add(new int[]{y, i}); g[y].add(new int[]{x, i}); // 建图,额外记录边的编号 } var dis = new int[n][2]; for (int i = 0; i < n; i++) if (i != source) dis[i][0] = dis[i][1] = Integer.MAX_VALUE; dijkstra(g, edges, destination, dis, 0, 0); int delta = target - dis[destination][0]; if (delta < 0) // -1 全改为 1 时,最短路比 target 还大 return new int[][]{}; dijkstra(g, edges, destination, dis, delta, 1); if (dis[destination][1] < target) // 最短路无法再变大,无法达到 target return new int[][]{}; for (var e : edges) if (e[2] == -1) // 剩余没修改的边全部改成 1 e[2] = 1; return edges; } // 朴素 Dijkstra 算法 // 这里 k 表示第一次/第二次 private void dijkstra(List<int[]> g[], int[][] edges, int destination, int[][] dis, int delta, int k) { int n = g.length; var vis = new boolean[n]; for (; ; ) { // 找到当前最短路,去更新它的邻居的最短路 // 根据数学归纳法,dis[x][k] 一定是最短路长度 int x = -1; for (int i = 0; i < n; ++i) if (!vis[i] && (x < 0 || dis[i][k] < dis[x][k])) x = i; if (x == destination) // 起点 source 到终点 destination 的最短路已确定 return; vis[x] = true; // 标记,在后续的循环中无需反复更新 x 到其余点的最短路长度 for (var e : g[x]) { int y = e[0], eid = e[1]; int wt = edges[eid][2]; if (wt == -1) wt = 1; // -1 改成 1 if (k == 1 && edges[eid][2] == -1) { // 第二次 Dijkstra,改成 w int w = delta + dis[y][0] - dis[x][1]; if (w > wt) edges[eid][2] = wt = w; // 直接在 edges 上修改 } // 更新最短路 dis[y][k] = Math.min(dis[y][k], dis[x][k] + wt); } } } }
python3 解法, 执行用时: 404 ms, 内存消耗: 19.2 MB, 提交时间: 2023-05-23 10:06:41
# 朴素Dijstra class Solution: def modifiedGraphEdges(self, n: int, edges: List[List[int]], source: int, destination: int, target: int) -> List[List[int]]: g = [[] for _ in range(n)] for i, (x, y, _) in enumerate(edges): g[x].append((y, i)) g[y].append((x, i)) # 建图,额外保存边的编号 dis = [[inf, inf] for _ in range(n)] dis[source] = [0, 0] def dijkstra(k: int) -> None: # 这里 k 表示第一次/第二次 vis = [False] * n while True: # 找到当前最短路,去更新它的邻居的最短路 # 根据数学归纳法,dis[x][k] 一定是最短路长度 x = -1 for y, (b, d) in enumerate(zip(vis, dis)): if not b and (x < 0 or d[k] < dis[x][k]): x = y if x == destination: # 起点 source 到终点 destination 的最短路已确定 return vis[x] = True # 标记,在后续的循环中无需反复更新 x 到其余点的最短路长度 for y, eid in g[x]: wt = edges[eid][2] if wt == -1: wt = 1 # -1 改成 1 if k == 1 and edges[eid][2] == -1: # 第二次 Dijkstra,改成 w w = delta + dis[y][0] - dis[x][1] if w > wt: edges[eid][2] = wt = w # 直接在 edges 上修改 # 更新最短路 dis[y][k] = min(dis[y][k], dis[x][k] + wt) dijkstra(0) delta = target - dis[destination][0] if delta < 0: # -1 全改为 1 时,最短路比 target 还大 return [] dijkstra(1) if dis[destination][1] < target: # 最短路无法再变大,无法达到 target return [] for e in edges: if e[2] == -1: # 剩余没修改的边全部改成 1 e[2] = 1 return edges