classSolution { public: vector<vector<int>> modifiedGraphEdges(int n, vector<vector<int>>& edges, int source, int destination, int target) { int k = 0; for (constauto& e: edges) { if (e[2] == -1) { ++k; } }
classSolution { publicint[][] modifiedGraphEdges(int n, int[][] edges, int source, int destination, int target) { intk=0; for (int[] e : edges) { if (e[2] == -1) { ++k; } }
if (dijkstra(source, destination, construct(n, edges, 0, target)) > target) { returnnewint[0][]; } if (dijkstra(source, destination, construct(n, edges, (long) k * (target - 1), target)) < target) { returnnewint[0][]; }
longleft=0, right = (long) k * (target - 1), ans = 0; while (left <= right) { longmid= (left + right) / 2; if (dijkstra(source, destination, construct(n, edges, mid, target)) >= target) { ans = mid; right = mid - 1; } else { left = mid + 1; } }
for (int[] e : edges) { if (e[2] == -1) { if (ans >= target - 1) { e[2] = target; ans -= target - 1; } else { e[2] = (int) (1 + ans); ans = 0; } } }
publicclassSolution { publicint[][] ModifiedGraphEdges(int n, int[][] edges, int source, int destination, int target) { int k = 0; foreach (int[] e in edges) { if (e[2] == -1) { ++k; } }
if (Dijkstra(source, destination, Construct(n, edges, 0, target)) > target) { returnnewint[0][]; } if (Dijkstra(source, destination, Construct(n, edges, (long) k * (target - 1), target)) < target) { returnnewint[0][]; }
long left = 0, right = (long) k * (target - 1), ans = 0; while (left <= right) { long mid = (left + right) / 2; if (Dijkstra(source, destination, Construct(n, edges, mid, target)) >= target) { ans = mid; right = mid - 1; } else { left = mid + 1; } }
foreach (int[] e in edges) { if (e[2] == -1) { if (ans >= target - 1) { e[2] = target; ans -= target - 1; } else { e[2] = (int) (1 + ans); ans = 0; } } }
return edges; }
publiclongDijkstra(int source, int destination, int[][] adjMatrix) { // 朴素的 dijkstra 算法 // adjMatrix 是一个邻接矩阵 int n = adjMatrix.Length; long[] dist = newlong[n]; Array.Fill(dist, int.MaxValue / 2); bool[] used = newbool[n]; dist[source] = 0;
for (int round = 0; round < n - 1; ++round) { int u = -1; for (int i = 0; i < n; ++i) { if (!used[i] && (u == -1 || dist[i] < dist[u])) { u = i; } } used[u] = true; for (int v = 0; v < n; ++v) { if (!used[v] && adjMatrix[u][v] != -1) { dist[v] = Math.Min(dist[v], dist[u] + adjMatrix[u][v]); } } }
return dist[destination]; }
publicint[][] Construct(int n, int[][] edges, long idx, int target) { // 需要构造出第 idx 种不同的边权情况,返回一个邻接矩阵 int[][] adjMatrix = newint[n][]; for (int i = 0; i < n; ++i) { adjMatrix[i] = newint[n]; Array.Fill(adjMatrix[i], -1); } foreach (int[] e in edges) { int u = e[0], v = e[1], w = e[2]; if (w != -1) { adjMatrix[u][v] = adjMatrix[v][u] = w; } else { if (idx >= target - 1) { adjMatrix[u][v] = adjMatrix[v][u] = target; idx -= (target - 1); } else { adjMatrix[u][v] = adjMatrix[v][u] = (int) (1 + idx); idx = 0; } } } return adjMatrix; } }
forroundinrange(n - 1): u = -1 for i inrange(n): if i notin used and (u == -1or dist[i] < dist[u]): u = i used.add(u) for v inrange(n): if v notin used and adj_matrix[u][v] != -1: dist[v] = min(dist[v], dist[u] + adj_matrix[u][v]) return dist[destination]
defconstruct(idx: int) -> List[List[int]]: # 需要构造出第 idx 种不同的边权情况,返回一个邻接矩阵 adj_matrix = [[-1] * n for _ inrange(n)] for u, v, w in edges: if w != -1: adj_matrix[u][v] = adj_matrix[v][u] = w else: if idx >= target - 1: adj_matrix[u][v] = adj_matrix[v][u] = target idx -= (target - 1) else: adj_matrix[u][v] = adj_matrix[v][u] = 1 + idx idx = 0 return adj_matrix k = sum(1for e in edges if e[2] == -1) if dijkstra(construct(0)) > target: return [] if dijkstra(construct(k * (target - 1))) < target: return []
left, right, ans = 0, k * (target - 1), 0 while left <= right: mid = (left + right) // 2 if dijkstra(construct(mid)) >= target: ans = mid right = mid - 1 else: left = mid + 1
for i, e inenumerate(edges): if e[2] == -1: if ans >= target - 1: edges[i][2] = target ans -= (target - 1) else: edges[i][2] = 1 + ans ans = 0
longlongdijkstra(int source, int destination, int **adj_matrix, int n) { // 朴素的 dijkstra 算法 // adj_matrix 是一个邻接矩阵 longlong dist[n]; int used[n]; memset(used, 0, sizeof(used)); for (int i = 0; i < n; i++) { dist[i] = INT_MAX / 2; } dist[source] = 0;
for (int round = 0; round < n - 1; ++round) { int u = -1; for (int i = 0; i < n; ++i) { if (!used[i] && (u == -1 || dist[i] < dist[u])) { u = i; } } used[u] = true; for (int v = 0; v < n; ++v) { if (!used[v] && adj_matrix[u][v] != -1) { dist[v] = fmin(dist[v], dist[u] + adj_matrix[u][v]); } } }
return dist[destination]; }
int** construct(int** edges, int edgesSize, longlong idx, int target, int **adj_matrix) { // 需要构造出第 idx 种不同的边权情况,返回一个邻接矩阵 for (int i = 0; i < edgesSize; i++) { int u = edges[i][0], v = edges[i][1], w = edges[i][2]; if (w != -1) { adj_matrix[u][v] = adj_matrix[v][u] = w; } else { if (idx >= target - 1) { adj_matrix[u][v] = adj_matrix[v][u] = target; idx -= (target - 1); } else { adj_matrix[u][v] = adj_matrix[v][u] = 1 + idx; idx = 0; } } } return adj_matrix; }
int** modifiedGraphEdges(int n, int** edges, int edgesSize, int* edgesColSize, int source, int destination, int target, int* returnSize, int** returnColumnSizes) { int k = 0; for (int i = 0; i < edgesSize; i++) { if (edges[i][2] == -1) { ++k; } }
int **adj_matrix = (int **)malloc(sizeof(int *) * n); for (int i = 0; i < n; i++) { adj_matrix[i] = (int *)malloc(sizeof(int) * n); memset(adj_matrix[i], 0xff, sizeof(int) * n); } if (dijkstra(source, destination, construct(edges, edgesSize, 0, target, adj_matrix), n) > target) { for (int i = 0; i < n; i++) { free(adj_matrix[i]); } free(adj_matrix); *returnSize = 0; returnNULL; } if (dijkstra(source, destination, construct(edges, edgesSize, (longlong) k * (target - 1), target, adj_matrix), n) < target) { for (int i = 0; i < n; i++) { free(adj_matrix[i]); } free(adj_matrix); *returnSize = 0; returnNULL; }
longlong left = 0, right = (longlong) k * (target - 1), ans = 0; while (left <= right) { longlong mid = (left + right) / 2; if (dijkstra(source, destination, construct(edges, edgesSize, mid, target, adj_matrix), n) >= target) { ans = mid; right = mid - 1; } else { left = mid + 1; } }
for (int i = 0; i < edgesSize; i++) { if (edges[i][2] == -1) { if (ans >= target - 1) { edges[i][2] = target; ans -= (target - 1); } else { edges[i][2] = 1 + ans; ans = 0; } } } *returnSize = edgesSize; *returnColumnSizes = edgesColSize; for (int i = 0; i < n; i++) { free(adj_matrix[i]); } free(adj_matrix); return edges; }
因此,我们可以考虑在进行 Dijkstra 算法的同时对边进行修改。在 Dijkstra 算法中,当我们遍历到节点 u 时,再去修改所有以 u 为端点的(且没有修改过的)边,此时就可以保证 d_{\min}(s, u) 的值都是最新的。同时,当我们枚举 u 的相邻节点 v 时,v 到 t 的最短路长度 d_{\min}(v, t) 要么与第一次 Dijkstra 算法中计算出的值相同,要么会变成一个非常大的值,使得 d_{\min}(s, u) + d_{\min}(v, t) 已经至少为 D(证明见下一段)。这样就只需要一次 Dijkstra 算法即可,时间复杂度降低为 O(n^2)。
关于 d_{\min}(v, t) 正确性的证明:如果此时的 d_{\min}(v, t) 与第一次 Dijkstra 算法中计算出的值不同,那么说明 v 到 t 的任意一条原来的(即所有可以修改的边的长度均为 1)最短路中,都有一条边的长度修改为了大于 1 的值。对于任意一条最短路:
如果修改的边的某个端点为 v,记这条边为 u’-v,由于 v 还没有遍历过,说明 u’ 已经遍历过,但 u’ 在 v 到 t 的最短路上,而最短路上不可能先经过离 t 较近的点 u’,再经过离 t 较远的点 v,这说明最终的最短路不可能从 s 到 u’ 到 v 再到 t,而是会跳过 v,因此这种情况并不会出现;
否则,记最短路上的 u’-v’ 这条边被修改过,并且遍历过的节点是 u’。根据 Dijkstra 算法的性质,我们有 d_{\min}(s, u’) \leq d_{\min}(s, u);根据最短路的性质,我们有 d_{\min}(v’, t) < d_{\min}(v, t),那么 u’-v’ 这条边被修改成的值就为 V = D - d_{\min}(s, u’) - d_{\min}(v’, t) > D - d_{\min}(s, u) - d_{\min}(v, t),v 到 t 的路径长度增加了至少 V - 1 \geq D - d_{\min}(s, u) - d_{\min}(v, t),即路径长度至少为 d’{\min}(v, t) = d{\min}(v, t) + V - 1 \geq D - d_{\min}(s, u)。此时,d_{\min}(s, u) + d’_{\min}(v, t) \geq D。
forroundinrange(n - 1): u = -1 for i inrange(n): if i notin used and (u == -1or dist[i] < dist[u]): u = i used.add(u) for v inrange(n): if v notin used and adj_matrix[u][v] != -1: if edges[adj_matrix[u][v]][2] != -1: dist[v] = min(dist[v], dist[u] + edges[adj_matrix[u][v]][2]) else: if op == 0: dist[v] = min(dist[v], dist[u] + 1) else: modify = target - dist[u] - from_destination[v] if modify > 0: dist[v] = min(dist[v], dist[u] + modify) edges[adj_matrix[u][v]][2] = modify else: edges[adj_matrix[u][v]][2] = target return dist
adj_matrix = [[-1] * n for _ inrange(n)] # 邻接矩阵中存储边的下标 for i, (u, v, w) inenumerate(edges): adj_matrix[u][v] = adj_matrix[v][u] = i from_destination = dijkstra(0, destination, adj_matrix) if from_destination[source] > target: return [] from_source = dijkstra(1, source, adj_matrix) if from_source[destination] != target: return [] return edges
longlong* dijkstra(int op, int source, int target, int **edges, int edgesSize, int** adj_matrix, int n, longlong *from_destination) { // 朴素的 dijkstra 算法 // adj_matrix 是一个邻接矩阵 int used[n]; longlong *dist = (longlong *)malloc(sizeof(longlong) * n); memset(used, 0, sizeof(used)); for (int i = 0; i < n; i++) { dist[i] = INT_MAX / 2; } dist[source] = 0;
for (int round = 0; round < n - 1; ++round) { int u = -1; for (int i = 0; i < n; ++i) { if (!used[i] && (u == -1 || dist[i] < dist[u])) { u = i; } } used[u] = true; for (int v = 0; v < n; ++v) { if (!used[v] && adj_matrix[u][v] != -1) { if (edges[adj_matrix[u][v]][2] != -1) { dist[v] = fmin(dist[v], dist[u] + edges[adj_matrix[u][v]][2]); } else { if (op == 0) { dist[v] = fmin(dist[v], dist[u] + 1); } else { int modify = target - dist[u] - from_destination[v]; if (modify > 0) { dist[v] = fmin(dist[v], dist[u] + modify); edges[adj_matrix[u][v]][2] = modify; } else { edges[adj_matrix[u][v]][2] = target; } } } } } } return dist; }
int** modifiedGraphEdges(int n, int** edges, int edgesSize, int* edgesColSize, int source, int destination, int target, int* returnSize, int** returnColumnSizes) { int **adj_matrix = (int **)malloc(sizeof(int *) * n); for (int i = 0; i < n; i++) { adj_matrix[i] = (int *)malloc(sizeof(int) * n); memset(adj_matrix[i], 0xff, sizeof(int) * n); } // 邻接矩阵中存储边的下标 for (int i = 0; i < edgesSize; ++i) { int u = edges[i][0], v = edges[i][1]; adj_matrix[u][v] = adj_matrix[v][u] = i; }
longlong from_destination[n]; memset(from_destination, 0, sizeof(from_destination)); longlong *ret = dijkstra(0, destination, target, edges, edgesSize, adj_matrix, n, from_destination); memcpy(from_destination, ret, sizeof(longlong) * n); free(ret); if (from_destination[source] > target) { for (int i = 0; i < n; i++) { free(adj_matrix[i]); } free(adj_matrix); *returnSize = 0; returnNULL; } longlong *from_source = dijkstra(1, source, target, edges, edgesSize, adj_matrix, n, from_destination); if (from_source[destination] != target) { for (int i = 0; i < n; i++) { free(adj_matrix[i]); } free(adj_matrix); free(from_source); *returnSize = 0; returnNULL; } for (int i = 0; i < n; i++) { free(adj_matrix[i]); } free(adj_matrix); free(from_source); *returnSize = edgesSize; *returnColumnSizes = edgesColSize; return edges; }