📅  最后修改于: 2023-12-03 14:58:35.001000             🧑  作者: Mango
给定一张 $n$ 个点 $m$ 条边的无向图。定义一条路径 $P$ 的“质量”定义为 $P$ 上边权的最大值。求出从 $s$ 到 $t$ 的所有路径中质量最小的路径的质量。
第一行两个整数 $n,m$。
接下来 $m$ 行,每行三个整数 $x,y,z$,表示点 $x,y$ 之间有一条边,边权为 $z$。
最后一行两个整数 $s,t$。
一个实数,四舍五入保留 $2$ 位小数。
$1\leq n\leq 500$,$1\leq m\leq 10^4$。
输入:
4 4
1 2 1
2 3 2
3 4 3
4 1 4
1 3
输出:
3.00
(二分答案 + DFS) $O(mlog_2w+n)$
由于质量单调不降,所以我们可以对答案进行二分。判断质量为 $mid$ 的路径是否存在,可以采用 DFS。
对于本题,DFS 的实现步骤为:
def dfs(x, mid):
queue = [x]
visited[x] = True
while queue:
node = queue.pop(0)
if node == t:
return True
for neighbor, weight in graph[node]:
if not visited[neighbor] and weight >= mid:
visited[neighbor] = True
queue.append(neighbor)
return False
l, r = 0, max_weight
while l < r:
mid = (l + r + 1) // 2
visited = [False] * (n + 1)
if dfs(s, mid):
l = mid
else:
r = mid - 1
print('{:.2f}'.format(l))
(迪杰斯特拉) $O(mlog_2w+n^2)$
本题还可以使用迪杰斯特拉算法求解。将边权当做距离,使用迪杰斯特拉算法求出 $s$ 到其他点的最短距离 $d_i$。最后,从 $s$ 到 $t$ 的所有路径中,选取最小的 $max_{i\in P} d_i$ 即可。
值得注意的是,迪杰斯特拉算法不能处理边权为负的情况。但是本题的边权是正数,所以可以使用迪杰斯特拉算法求解。
import heapq
INF = 10**6
d = [INF] * (n + 1)
d[s] = 0
heap = [(0, s)]
while heap:
dist, node = heapq.heappop(heap)
if node == t:
break
if d[node] < dist:
continue
for neighbor, weight in graph[node]:
new_dist = max(dist, weight)
if new_dist < d[neighbor]:
d[neighbor] = new_dist
heapq.heappush(heap, (new_dist, neighbor))
print('{:.2f}'.format(d[t]))
(最短路,把边权取反后求最短路) $O(mlog_2w+n^2)$
由于边权都是正数,因此我们可以采用一种奇技淫巧:把边权取反后再求最短路。
这种方式的思想是,最短路径上边权最小,所以把路径中的所有边权取反后,原来最小的路径就变成了最大的路径,原来次小的路径就变成了次大的路径。
def dijkstra(s):
d = [INF] * (n + 1)
d[s] = 0
heap = [(0, s)]
while heap:
dist, node = heapq.heappop(heap)
if d[node] < dist:
continue
for neighbor, weight in graph[node]:
new_dist = -1 * min(dist, -1 * weight)
if new_dist < d[neighbor]:
d[neighbor] = new_dist
heapq.heappush(heap, (new_dist, neighbor))
return d
d1 = dijkstra(s)
print('{:.2f}'.format(-1 * d1[t]))
(SPFA) $O(km+n^2)$
SPFA 方法也可以用于解决此问题。首先,给所有的边权值取反,然后进行 SPFA 求出 $s$ 到 $t$ 的最短路径,最终再将答案求反输出即可。
SPFA 这种算法的缺点是,如果图中有负环,它将一直在负环中循环。对于本题,边权都是正数,因此可以使用 SPFA 算法。
def spfa(s):
dist = [INF] * (n + 1)
dist[s] = 0
queue = [s]
in_queue = [False] * (n + 1)
in_queue[s] = True
while queue:
node = queue.pop(0)
in_queue[node] = False
for neighbor, weight in graph[node]:
if dist[node] + weight < dist[neighbor]:
dist[neighbor] = dist[node] + weight
if not in_queue[neighbor]:
queue.append(neighbor)
in_queue[neighbor] = True
return dist
d1 = spfa(s)
print('{:.2f}'.format(-1 * d1[t]))