📜  门| GATE CS 2020 |问题 13(1)

📅  最后修改于: 2023-12-03 15:42:12.388000             🧑  作者: Mango

门| GATE CS 2020 |问题 13

本篇文章将介绍 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()