📅  最后修改于: 2023-12-03 15:42:12.388000             🧑  作者: Mango
本篇文章将介绍 GATE CS 2020 的问题 13 ,该问题考查了计算机科学中的图论知识点。
给定一个无向图 $G=(V,E)$,其中 $V$ 为点集,$E$ 为边集。假设 $G$ 是联通图,即对于任意的 $u,v\in V$,都存在一条从 $u$ 到 $v$ 的路径。定义一个点对 $(u,v)$ 为“十足值点对”,当且仅当在图中存在一条从 $u$ 到 $v$ 的路径,使得该路径上的所有边的权重都大于或等于 $w$,其中 $w$ 是一个非负整数。
你的任务是计算有多少种十足值点对满足 $\text{dist}(u,v)=k$,其中 $\text{dist}(u,v)$ 是 $u$ 到 $v$ 的最短路径长度。
从题目可知,我们需要对非负整数 $w$ 分别构建 $w$ 条边权值的最小生成树。对于构建的各个最小生成树,我们可以采取深度优先遍历的方式,来计算所有点对的最短路径。计算所有点对的最短路径所需要的时间复杂度为 $O(V^3)$。因此,总的时间复杂度为 $O(W(V+E)V^3)$,其中 $W$ 表示边权最大值。
以下代码片段以 Python 代码为例,展示了如何实现该算法:
from typing import List, Tuple
import heapq
def prim(n: int, edges: List[Tuple[int, int, int]], w: int) -> List[Tuple[int, int]]:
"""
构建边权值大于或等于 w 的最小生成树
"""
adj_list = [[] for _ in range(n)]
for u, v, wt in edges:
if wt >= w:
adj_list[u].append((v, wt))
adj_list[v].append((u, wt))
visited = [False] * n
dist = [float('inf')] * n
parent = [-1] * n
dist[0] = 0
pq = [(0, 0)]
while pq:
_, u = heapq.heappop(pq)
if visited[u]:
continue
visited[u] = True
for v, wt in adj_list[u]:
if not visited[v] and wt < dist[v]:
dist[v] = wt
parent[v] = u
heapq.heappush(pq, (wt, v))
return [(u, v) for u, v in enumerate(parent) if v != -1]
def floyd_warshall(n: int, edges: List[Tuple[int, int, int]]) -> List[List[int]]:
"""
利用 Floyd-Warshall 算法计算任意两点之间的最短路径
"""
dist = [[float('inf')] * n for _ in range(n)]
for u in range(n):
dist[u][u] = 0
for u, v, wt in edges:
dist[u][v] = dist[v][u] = wt
for k in range(n):
for i in range(n):
for j in range(n):
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
return dist
def find_pairs(n: int, edges: List[Tuple[int, int, int]]) -> int:
"""
计算有多少种“十足值点对”
"""
max_wt = max(wt for _, _, wt in edges)
min_weights = [float('inf')] + sorted(set(wt for _, _, wt in edges))
ans = 0
for i in range(len(min_weights)):
mst = prim(n, edges, min_weights[i])
dist = floyd_warshall(n, edges)
for u, v in mst:
if dist[u][v] == i + 1:
ans += 1
return ans
其中,最外层的函数 find_pairs()
是一个统计答案的函数,其内部依次实现了构建最小生成树函数 prim()
和采用 Floyd-Warshall 算法计算任意两点之间的最短路径函数 floyd_warshall()
。